Email from Tom, 18 January:

1. “Polish” SV calls using Illumina data: https://github.com/smehringer/SViper

Please explore the above - get install and tested.

Nanopore VCF files:

SViper says: >The vcf file must be a structural variant format (tags instead of sequences, e.g. ). ALso the INFO field must include the END tag, giving the end position of the variant, as well as the SVLEN tag in case of insertions.

Then we need to map Illumina ID to the Nanopore VCF and figure out how to run the polishing.

Once done we need to summarise and describe the SV’s a little with some annotations etc - i will make a start with doing this part and we catchup once you have looked at the polishing

2. catchup with Jack on repeats (both MIKK panel and Nanopore assemblies). - create one plot for each paper

  1. Fecundity - i will send you the data and a description of what exactly it is later today.
  1. Add to txt within the two documents - we can catch-up on this later in the week.

Polish SV calls with Illumina data

Setup

Working directory on EBI cluster: /hps/research1/birney/users/ian/mikk_paper/mikk_genome/sv_analysis GitHub repo: https://github.com/brettellebi/mikk_genome

conda envs

sv_env

# Make conda env
mamba create -n sv_env
conda activate sv_env
# Install packages
mamba install -c bioconda bcftools sniffles
mamba install -c conda-forge r-base r-tidyverse
# Export to file
conda env export > envs/sv_env/sv_env.yaml

baseR

# Activate
conda activate baseR
# Export
conda env export > envs/baseR/baseR.yaml

renv

# Initiate
renv::init()
# Snapshot
renv::snapshot()
# Restore
renv::restore()

Source

library(here)
source(here::here("code", "scripts", "sv_analysis", "source.R"))

Nanopore VCF

/hps/research1/birney/users/adrien/analyses/medaka_DNA_promethion/brain_run2/DNA_analysis/results/SV/sniffles_all/merged.vcf

Created with:

# First used:
sniffles \
  --min_support 3 \
  --max_num_splits 7 \
  --max_distance 1000 \
  --min_length 50 \
  --minmapping_qual 20 \
  --min_seq_size 1000 \
  --allelefreq 0.1 \
  -t {threads} \
  -m {input_bam} \
  -v {output_vcf}

Adrien: >Then I filtered and merged all the variants from the different samples together with survivor and recalled variants a second time in forced mode using the merged set with sniffles again using the same options.

Copy to working directory

# With sequences
nano_raw=/hps/research1/birney/users/adrien/indigene/analyses/indigene_nanopore_DNA/brain_run2/DNA_analysis/results/SV/sniffles_all_OLD/merged.vcf
out_path=../sv_analysis/vcfs/ont_raw_with_seq.vcf
## Copy
cp $nano_raw $out_path

# Without sequences
nano_raw=/hps/research1/birney/users/adrien/indigene/analyses/indigene_nanopore_DNA/brain_run2/DNA_analysis/results/SV/sniffles_all/merged.vcf
out_path=../sv_analysis/vcfs/ont_raw.vcf
## Copy
cp $nano_raw $out_path

Rename samples

With sequences
conda activate sv_env

in_vcf=../sv_analysis/vcfs/ont_raw_with_seq.vcf
sample_file=data/sv_analysis/20210205_ont_raw_samples_file.txt
out_vcf=../sv_analysis/vcfs/ont_raw_with_seq_rehead.vcf

# Make samples key file
bcftools query -l $in_vcf \
  > tmp1
cut -f4 -d'/' tmp1 | cut -f1 -d'_' \
  > tmp2
paste -d' ' tmp1 tmp2 > $sample_file
rm tmp1 tmp2

# Rename VCF
bcftools reheader \
  --samples $sample_file \
  --output $out_vcf \
  $in_vcf
Without sequences
conda activate sv_env

in_vcf=../sv_analysis/vcfs/ont_raw.vcf
sample_file=data/sv_analysis/20210212_ont_raw_samples_file.txt
out_vcf=../sv_analysis/vcfs/ont_raw_rehead.vcf

# Make samples key file
bcftools query -l $in_vcf \
  > tmp1
cut -f4 -d'/' tmp1 | cut -f1 -d'_' \
  > tmp2
paste -d' ' tmp1 tmp2 > $sample_file
rm tmp1 tmp2

# Rename VCF
bcftools reheader \
  --samples $sample_file \
  --output $out_vcf \
  $in_vcf

Get stats

With sequences
conda activate sv_mikk

in_vcf=../sv_analysis/vcfs/ont_raw_with_seq.vcf
stats_out=../sv_analysis/vcfs/ont_raw_with_seq.stats

# Get stats
bcftools stats \
  $in_vcf \
    > $stats_out
Without sequences
conda activate sv_mikk

in_vcf=../sv_analysis/vcfs/ont_raw.vcf
stats_out=../sv_analysis/vcfs/ont_raw.stats

# Get stats
bcftools stats \
  $in_vcf \
    > $stats_out

Split per sample

With sequences
conda activate sv_mikk

in_vcf=../sv_analysis/vcfs/ont_raw_with_seq_rehead.vcf
out_dir=../sv_analysis/vcfs/ont_raw_with_seq_rehead_per_sample

mkdir -p $out_dir

# Split by sample
bcftools +split \
  $in_vcf \
  --output $out_dir
Without sequences
conda activate sv_mikk

in_vcf=../sv_analysis/vcfs/ont_raw_rehead.vcf
out_dir=../sv_analysis/vcfs/ont_raw_rehead_per_sample

mkdir -p $out_dir

# Split by sample
bcftools +split \
  $in_vcf \
  --output $out_dir

Illumina VCF

Copy to working directory

conda activate sv_env

in_vcf=/nfs/research1/birney/projects/medaka/inbred_panel/medaka-alignments-release-94/vcf/medaka_inbred_panel_ensembl_new_reference_release_94.vcf
out_vcf=../sv_analysis/vcfs/ill_raw.vcf.gz

# Compress and copy
bsub \
  -M 30000 \
  -o ../log/20210208_comp_ill.out \
  -e ../log/20210208_comp_ill.err \
bsub -Is bash \
  """
  conda activate sv_env ;
  bcftools view \
    --output-type z \
    --output $out_vcf \
    $in_vcf
  """  

Rename and filter for ONT samples

Pull out IDs for relevant samples
ont_samples = here::here("data", "sv_analysis", "20210205_ont_raw_samples_file.txt")
ill_samples = here::here("data","20200206_cram_id_to_line_id.txt")
out_file = here::here("data", "sv_analysis", "20210205_ill_key_ont_samples.txt")
out_samples = here::here("data", "sv_analysis", "20210205_ont_samples_only.txt")

# Read in tables

ont_key = read.table(ont_samples)
ill_key = read.table(ill_samples, comment.char = "\"", header = T) %>% 
  dplyr::mutate(line = gsub("_", "-", line))

# Find matches
out = ill_key[ill_key$line %in% ont_key$V2, ]

# Write to files
## Key file
readr::write_delim(out, out_file, delim = " ", col_names = F)
## Just samples
readr::write_lines(out$cram_file, out_samples)
Rename and filter
in_vcf=../sv_analysis/vcfs/ill_raw.vcf.gz
samples_file=data/sv_analysis/20210205_ont_samples_only.txt
samples_key=data/sv_analysis/20210205_ill_key_ont_samples.txt
out_vcf=../sv_analysis/vcfs/ill_raw_rehead.vcf.gz
out_dir=../sv_analysis/vcfs/ill_raw_rehead_per_sample

mkdir -p $out_dir

# Filter for target samples and rehead
bcftools view \
  --samples-file $samples_file \
  --output-type u \
  $in_vcf |\
    bcftools reheader \
      --samples $samples_key \
      --output $out_vcf

# Split by sample
bcftools +split \
  $out_vcf \
  --output $out_dir

BAMs

Illumina .bam files

Copy to local.

sample_key=data/sv_analysis/20210205_ill_key_ont_samples.txt
ill_bam_dir=/nfs/research1/birney/projects/medaka/inbred_panel/medaka-alignments-release-94/bam
out_dir=../sv_analysis/bams

mkdir -p $out_dir 

# Copy over
for sample in $(cut -f1 -d' ' $sample_key ) ; do
  cp $ill_bam_dir/$sample.bai $out_dir ;
done  

# SViper needs bams in .bam.bai format. Original {sample}.bai files need to be copied to {sample}.bam.bai
for file in $( find $out_dir/*.bai ) ; do
  new_filename=$( echo $file | sed 's/.bai/.bam.bai/g' ) ;
  mv $file $new_filename ;
done

Nanopore .bam files

Sit here: /hps/research1/birney/users/adrien/indigene/analyses/indigene_nanopore_DNA/brain_run2/DNA_analysis/results/SV/ngmlr_alignments/

Polish Nanopore reads with SViper

Create Singularity container

module load singularity

# Build
singularity build \
  --remote ../sing_conts/sviper.sif \
  envs/sviper/20210204_sviper.def
  
# Open interactive shell
bsub -Is "singularity shell ../sing_conts/sviper.sif"
# Works! 

Test

# Load singularity
module load singularity
# Pull image built with `envs/sviper/20210204_sviper.def`
bsub -M 30000 -n 4 -Is "singularity shell ../sing_conts/sviper.sif"

#######################
# Variables
#######################
## Container
container=../sing_conts/sviper.sif
## Sample
sample=11-1
sample_key=data/sv_analysis/20210205_ill_key_ont_samples.txt
## VCF to polish
ont_vcf=../sv_analysis/vcfs/ont_raw_rehead_per_sample/$sample.vcf
## Illumina BAM
ill_cram_id=$(grep $sample $sample_key | cut -f1 -d' ')
ill_bam_dir=../sv_analysis/bams
ill_bam=$ill_bam_dir/$ill_cram_id.bam
## Nanopore BAM
ont_bam_dir=/hps/research1/birney/users/adrien/indigene/analyses/indigene_nanopore_DNA/brain_run2/DNA_analysis/results/SV/ngmlr_alignments
ont_bam=$(find $ont_bam_dir/$sample*.bam)
## Reference
ref=../refs/Oryzias_latipes.ASM223467v1.dna.toplevel.fa
## Output directory
out_dir=../sv_analysis/vcfs/sviper
mkdir -p $out_dir

#######################
# TEST call sviper 
#######################
sviper \
  --candidate-vcf $ont_vcf \
  --short-read-bam $ill_bam \
  --long-read-bam $ont_bam \
  --reference $ref \
  --output-prefix $out_dir/$sample

True

# Load singularity
module load singularity
# Pull image built with `envs/sviper/20210204_sviper.def`
bsub -M 30000 -n 4 -Is "singularity shell ../sing_conts/sviper.sif"

#######################
# Variables
#######################
## Sample
sample=11-1
sample_key=data/sv_analysis/20210205_ill_key_ont_samples.txt
## VCF to polish
ont_vcf=../sv_analysis/vcfs/ont_raw_rehead_per_sample/$sample.vcf
## Illumina BAM
ill_cram_id=$(grep $sample $sample_key | cut -f1 -d' ')
ill_bam_dir=../sv_analysis/bams
ill_bam=$ill_bam_dir/$ill_cram_id.bam
## Nanopore BAM
ont_bam_dir=/hps/research1/birney/users/adrien/indigene/analyses/indigene_nanopore_DNA/brain_run2/DNA_analysis/results/SV/ngmlr_alignments
ont_bam=$(find $ont_bam_dir/$sample*.bam)
## Reference
ref=../refs/Oryzias_latipes.ASM223467v1.dna.toplevel.fa
## Container
container=../sing_conts/sviper.sif
## Output directory
out_dir=../sv_analysis/vcfs/sviper
mkdir -p $out_dir

#######################
# TEST call sviper 
#######################
sviper \
  --candidate-vcf $ont_vcf \
  --short-read-bam $ill_bam \
  --long-read-bam $ont_bam \
  --reference $ref \
  --output-prefix $out_dir/$sample
  
#######################
# TRUE call sviper 
####################### 
module load singularity

# Global variables
## Sample key
sample_key=data/sv_analysis/20210205_ill_key_ont_samples.txt
## BAM dirs
ill_bam_dir=../sv_analysis/bams
ont_bam_dir=/hps/research1/birney/users/adrien/indigene/analyses/indigene_nanopore_DNA/brain_run2/DNA_analysis/results/SV/ngmlr_alignments
## Reference
ref=../refs/Oryzias_latipes.ASM223467v1.dna.toplevel.fa
## Container
container=../sing_conts/sviper.sif
## Output directory
out_dir=../sv_analysis/vcfs/sviper
mkdir -p $out_dir

for sample in $(cut -f2 -d' ' $sample_key | tail -n+2 ) ; do
  # Set variables
  
  ## VCF to polish
  ont_vcf=../sv_analysis/vcfs/ont_raw_rehead_per_sample/$sample.vcf
  ## Illumina BAM
  ill_cram_id=$(grep " $sample" $sample_key | cut -f1 -d' ')
  ill_bam=$ill_bam_dir/$ill_cram_id.bam
  ## Nanopore BAM
  ont_bam=$(find $ont_bam_dir/$sample*.bam)

  # Run SViper
  bsub \
    -M 30000 \
    -n 16 \
    -o ../log/20210212_sviper_$sample.out \
    -e ../log/20210212_sviper_$sample.err \
    """
    singularity exec $container \
      sviper \
        --candidate-vcf $ont_vcf \
        --short-read-bam $ill_bam \
        --long-read-bam $ont_bam \
        --reference $ref \
        --output-prefix $out_dir/$sample
    """
done

# 4-2 and 7-2 failed with no error message

Merge

# Get list of vcf paths
in_dir=../sv_analysis/vcfs/sviper
out_dir=$in_dir/merged
mkdir -p $out_dir
in_vcfs=$(find $in_dir/*.vcf | tr '\n' ' ')

bcftools merge \
  --output $out_dir/all.vcf\
  $in_vcfs
  
# Requires them to be bgzipped

# Try with Picard
in_dir=../sv_analysis/vcfs/sviper
out_dir=$in_dir/merged
mkdir -p $out_dir
find $in_dir/*.vcf > tmp.list

picard MergeVcfs \
  I=tmp.list \
  O=$out_dir/merged.vcf.gz

rm tmp.list
#Exception in thread "main" java.lang.IllegalArgumentException: Input file /hps/research1/birney/users/ian/mikk_paper/mikk_genome/../sv_analysis/vcfs/sviper/117-2.vcf has sample entries that don't match the other files.
module load singularity

# Build
singularity build \
  --remote ../sing_conts/survivor.sif \
  envs/survivor/20210217_survivor.def
  
# Open interactive shell
bsub -Is "singularity shell ../sing_conts/survivor.sif"
# Works! 

–>

Get data from SViper

in_dir=../sv_analysis/vcfs/sviper
out_dir=data/sv_analysis/20210217_sviper_filter_pass

mkdir -p $out_dir

for in_vcf in $(find $in_dir/*vcf) ; do
  sample=$(basename $in_vcf | cut -f1 -d'.' ) ;
  bcftools query \
    --include 'FILTER="PASS"' \
    --exclude 'GT~"\."' \
    --format '%CHROM,%POS,%ALT,%INFO/SVLEN,%INFO/SVTYPE,%INFO/CHR2,%INFO/END,[%GT],[%LN],[%ST]\n' \
  --output $out_dir/$sample.csv \
  $in_vcf ;
done

Get data from original VCF

in_dir=../sv_analysis/vcfs/ont_raw_rehead_per_sample
out_dir=data/sv_analysis/20210217_raw_ont_filter_pass

mkdir -p $out_dir

for in_vcf in $(find $in_dir/*vcf) ; do
  sample=$(basename $in_vcf | cut -f1 -d'.' ) ;
  bcftools query \
    --include 'FILTER="PASS"' \
    --exclude 'GT~"\."' \
    --format '%CHROM,%POS,%ALT,%INFO/SVLEN,%INFO/SVTYPE,%INFO/CHR2,%INFO/END,[%GT],[%LN],[%ST]\n' \
  --output $out_dir/$sample.csv \
  $in_vcf ;
done

Get polish stats

in_dir=../sv_analysis/vcfs/sviper
out_dir=data/sv_analysis/20210226_polish_stats

mkdir -p $out_dir

for in_vcf in $(find $in_dir/*vcf) ; do
  sample=$(basename $in_vcf | cut -f1 -d'.' ) ;
  bcftools query \
    --include 'FILTER="PASS"' \
    --exclude 'GT~"\."' \
    --format '%CHROM,%POS,%FILTER,%INFO/SVTYPE,[%LN]\n' \
  --output $out_dir/$sample.csv \
  $in_vcf ;
done

Analysis

Read in SV data

SViper polished

in_dir = here::here("data", "sv_analysis/20210217_raw_ont_filter_pass")

in_files = list.files(in_dir, full.names = T)
names(in_files) = basename(in_files) %>% 
  str_remove(".csv")

sv_df_raw = lapply(in_files, function(in_file){
  df = readr::read_csv(in_file,
                       col_names = c("CHROM", "POS", "ALT", "SVLEN", "SVTYPE", "CHR2", "END", "GT", "LN", "ST"),
                       col_types = c("ciciccicic"))
  
  return(df)
}) %>% 
  dplyr::bind_rows(.id = "SAMPLE") %>% 
  # add "chr" to beginning of CHROM column
  dplyr::mutate(CHROM = paste("chr", CHROM, sep = ""))

ONT raw

sv_df = list("polished" = sv_df_pol,
             "raw" = sv_df_raw) %>% 
  dplyr::bind_rows(.id = "DATASET") %>% 
  # factor samples and dataset
  dplyr::mutate(SAMPLE = factor(SAMPLE, levels = ont_samples),
                DATASET = factor(DATASET, levels = c("raw", "polished")))

Combine into single df

Plot counts of SV types (total)

# Get order
type_order = dplyr::count(sv_df, SVTYPE) %>% 
  dplyr::arrange(desc(n)) %>% 
  dplyr::pull(SVTYPE)

# Set palette
pal_svtype = grDevices::colorRampPalette(pal_brainbow)(length(ont_samples))
names(pal_svtype) = ont_samples

Plot counts of SV types (per sample)

Get order of SV type by frequency

sv_counts_all = sv_df %>% 
  dplyr::filter(DATASET == "polished") %>%
  group_by(SAMPLE, SVTYPE) %>% 
  summarise(N = n()) %>% 
  dplyr::mutate(FACET = "TOTAL") %>% 
  dplyr::ungroup()
`summarise()` has grouped output by 'SAMPLE'. You can override using the `.groups` argument.

All

# Create DF with SAMPLE for binding later
sv_df_pol_samps = sv_df %>% 
  # exclude raw data, take only polished
  dplyr::filter(DATASET == "polished") %>% 
  # select only target cols
  dplyr::select(CHROM, POS, SVTYPE, LN, SAMPLE)

# Create DF without SAMPLE for detecting duplicates
sv_df_pol_dupes = sv_df %>% 
  # exclude raw data, take only polished
  dplyr::filter(DATASET == "polished") %>% 
  # select only target cols
  dplyr::select(CHROM, POS, SVTYPE, LN)

## Get unique rows
uq_svs = sv_df_pol_dupes[!(duplicated(sv_df_pol_dupes) | duplicated(sv_df_pol_dupes, fromLast = T)), ]

# Join back with other variables
sv_sings = dplyr::right_join(sv_df_pol_samps, uq_svs)
Joining, by = c("CHROM", "POS", "SVTYPE", "LN")
knitr::kable(head(sv_sings))
CHROM POS SVTYPE LN SAMPLE
chr1 15558 TRA 1 11-1
chr1 116343 DEL 530 11-1
chr1 131785 INS 56 11-1
chr1 230567 TRA 1 11-1
chr1 231887 DEL 103 11-1
chr1 231872 TRA 1 11-1

Singletons

# Get singleton counts
sv_counts_sings = sv_sings %>%
  dplyr::group_by(SAMPLE, SVTYPE) %>% 
  dplyr::summarise(N = n()) %>% 
  dplyr::mutate(FACET = "SINGLETONS") %>% 
  dplyr::ungroup()

summarise() has grouped output by ‘SAMPLE’. You can override using the .groups argument.

# Bind DFs
sv_counts = dplyr::bind_rows(sv_counts_all,
                             sv_counts_sings) %>% 
  dplyr::mutate(FACET = factor(FACET, levels = c("TOTAL", "SINGLETONS")),
                SVTYPE = factor(SVTYPE, levels = type_order))

# Set palette
pal_svcounts = grDevices::colorRampPalette(pal_smrarvo)(length(ont_samples))
names(pal_svcounts) = ont_samples

# Plot
svtype_counts_plot = sv_counts %>% 
  ggplot() +
    geom_col(aes(SAMPLE, N, fill = SAMPLE)) +
    facet_grid(rows = vars(FACET),
               cols = vars(SVTYPE),scales = "free_y") +
    scale_fill_manual(values = pal_svcounts) +
    theme_cowplot() +
    theme(strip.background = element_blank(),
          axis.text.x = element_text(size = 5,angle = 45,hjust = 1),
          strip.text.x = element_text(face = "bold")) +
    guides(fill = F) +
    xlab("Sample") +
    ylab("Count")

svtype_counts_plot 

Bind together and plot

ggplotly(svtype_counts_plot)
ggplotly(svtype_counts_plot)
final_svtype = ggdraw() +
  draw_plot(svtype_plt, x = 0, y = 0, width = .6, height = 1) +
  draw_plot(svtype_hists[[1]], x = .6, y = .5, width =0.2, height = 0.5) +
  draw_plot(svtype_hists[[2]], x = .8, y = .5, width =0.2, height = 0.5) +
  draw_plot(svtype_hists[[3]], x = .6, y = 0, width =0.2, height = 0.5) +
  draw_plot(svtype_hists[[4]], x = .8, y = 0, width =0.2, height = 0.5) +
  draw_plot_label(label = c("A", "B"), size = 15,
                  x = c(0, .6), y = c(1, 1))

final_svtype
ggsave(here::here("plots", "sv_analysis", "20210225_sv_type_counts.svg"),
       device = "svg",
       units = "cm",
       width = 30,
       height = 10)

ggsave(here::here("plots", "sv_analysis", "20210225_sv_type_counts.png"),
       device = "png",
       dpi = 400,
       units = "cm",
       width = 30,
       height = 10)

–>

Circos plots

SVGs become very large (~80 MB). Hence PNG.

Create scaffold

# Read in chromosome data
chroms = read.table(here::here("data/Oryzias_latipes.ASM223467v1.dna.toplevel.fa_chr_counts.txt")) %>% 
  dplyr::select(chr = V1, end = V2) %>% 
  dplyr::mutate(chr = paste("chr", chr, sep = ""),
                start = 0,
                end = as.numeric(end)) %>% 
  dplyr::select(chr, start, end)

DEL

sv_dels = sv_df %>% 
  dplyr::filter(DATASET == "polished",
                SVTYPE == "DEL") %>% 
  dplyr::select(CHROM, POS, END, SAMPLE, LN) %>%
  dplyr::mutate(SAMPLE = factor(SAMPLE, levels = ont_samples_pol)) %>% 
  split(., f = .$SAMPLE)
out_plot = here::here("plots", "sv_analysis", "20210224_sv_dels_lines.png")
png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 400)

# Get max value for `ylim`
max_len = max(sapply(sv_dels, function(sample) max(sample$LN)))
max_len = round.choose(max_len, 1e5, dir = 1)

# Choose palette
pal = grDevices::colorRampPalette(pal_smrarvo)(length(sv_dels))

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 14))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

counter = 0
lapply(sv_dels, function(sample) {
  # Set counter
  counter <<- counter + 1
  # Create track
  circos.genomicTrack(sample,
    panel.fun = function(region, value, ...) {
      circos.genomicLines(region,
                          value,
                          type = "h",
                          col = pal[counter],
                          cex = 0.05)
  },
  track.height = 0.07,
  bg.border = NA,
  ylim = c(0, max_len))
  
  # Add SV length y-axis label
  circos.yaxis(side = "right",
             at = c(2.5e5, max_len),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  

  # Add SAMPLE y-axis label
  circos.text(2e6, 2.5e5,
              labels = names(sv_dels)[counter],
              sector.index = "chr1",
              cex = 0.4*par("cex"))
})


circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

INS

NOTE: 25982/351996 insertions have an END that is less than POS. Make the END the same as POS for the purposes of plotting their location.

sv_ins = sv_df %>% 
  dplyr::filter(DATASET == "polished",
                SVTYPE == "INS") %>% 
  dplyr::select(CHROM, POS, END, SAMPLE, LN) %>%
  # Factorise SAMPLE to order
  dplyr::mutate(SAMPLE = factor(SAMPLE, levels = ont_samples_pol)) %>% 
  # if END is less than POS, make it the same as POS
  dplyr::mutate(END = dplyr::if_else(END < POS, POS, END)) %>% 
#  dplyr::slice_sample(n = 10000) %>% 
  split(., f = .$SAMPLE)
out_plot = here::here("plots", "sv_analysis", "20210224_sv_ins_lines.png")
png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 400)

# Get max value for `ylim`
max_len = max(sapply(sv_ins, function(sample) max(sample$LN)))
max_len = round.choose(max_len, 1e5, dir = 1)

# Choose palette
pal = fishualize::fish(n = length(sv_ins), option = "Cirrhilabrus_solorensis")

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 14))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

counter = 0
lapply(sv_ins, function(sample) {
  # Set counter
  counter <<- counter + 1
  # Create track
  circos.genomicTrack(sample,
    panel.fun = function(region, value, ...) {
      circos.genomicLines(region,
                          value,
                          type = "h",
                          col = pal[counter],
                          cex = 0.05)
  },
  track.height = 0.07,
  bg.border = NA,
  ylim = c(0, max_len))
  
  # Add SV length y-axis label
  circos.yaxis(side = "right",
             at = c(2.5e5, max_len),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  

  # Add SAMPLE y-axis label
  circos.text(2e6, 2.5e5,
              labels = names(sv_ins)[counter],
              sector.index = "chr1",
              cex = 0.4*par("cex"))
})


circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

DUP

NOTE: 307/26823 duplications have an END that is less than POS. Make the END the same as POS.

sv_dups = sv_df %>% 
  dplyr::filter(DATASET == "polished",
                SVTYPE == "DUP") %>% 
  dplyr::select(CHROM, POS, END, SAMPLE, LN) %>%
  dplyr::mutate(SAMPLE = factor(SAMPLE, levels = ont_samples_pol)) %>% 
  # if END is less than POS, make it the same as POS
  dplyr::mutate(END = dplyr::if_else(END < POS, POS, END)) %>% 
#  dplyr::slice_sample(n = 10000) %>% 
  split(., f = .$SAMPLE)
out_plot = here::here("plots", "sv_analysis", "20210224_sv_dups_lines.png")
png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 400)

# Get max value for `ylim`
max_len = max(sapply(sv_dups, function(sample) max(sample$LN)))
max_len = round.choose(max_len, 1e5, dir = 1)

# Choose palette
pal = fishualize::fish(n = length(sv_dups), option = "Gramma_loreto")

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 14))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

counter = 0
lapply(sv_dups, function(sample) {
  # Set counter
  counter <<- counter + 1
  # Create track
  circos.genomicTrack(sample,
    panel.fun = function(region, value, ...) {
      circos.genomicLines(region,
                          value,
                          type = "h",
                          col = pal[counter],
                          cex = 0.05)
  },
  track.height = 0.07,
  bg.border = NA,
  ylim = c(0, max_len))
  
  # Add SV length y-axis label
  circos.yaxis(side = "right",
             at = c(2.5e5, max_len),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  

  # Add SAMPLE y-axis label
  circos.text(2e6, 2.5e5,
              labels = names(sv_dups)[counter],
              sector.index = "chr1",
              cex = 0.4*par("cex"))
})


circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

INV

sv_invs = sv_df %>% 
  dplyr::filter(DATASET == "polished",
                SVTYPE == "INV") %>% 
  dplyr::select(CHROM, POS, END, SAMPLE, LN) %>%
  dplyr::mutate(SAMPLE = factor(SAMPLE, levels = ont_samples_pol)) %>% 
  # if END is less than POS, make it the same as POS
#  dplyr::mutate(END = dplyr::if_else(END < POS, POS, END)) %>% 
#  dplyr::slice_sample(n = 10000) %>% 
  split(., f = .$SAMPLE)
out_plot = here::here("plots", "sv_analysis", "20210224_sv_invs_lines.png")
png(out_plot,
    width = 20,
    height = 20,
    units = "cm",
    res = 400)

# Get max value for `ylim`
max_len = max(sapply(sv_invs, function(sample) max(sample$LN)))
max_len = round.choose(max_len, 1e5, dir = 1)

# Choose palette
pal = fishualize::fish(n = length(sv_invs), option = "Lepomis_megalotis")

# Set parameters
## Decrease cell padding from default c(0.02, 1.00, 0.02, 1.00)
circos.par(cell.padding = c(0, 0, 0, 0),
           track.margin = c(0, 0),
           gap.degree = c(rep(1, nrow(chroms) - 1), 14))
# Initialize plot
circos.initializeWithIdeogram(chroms,
                              plotType = c("axis", "labels"),
                              major.by = 1e7,
                              axis.labels.cex = 0.25*par("cex"))

counter = 0
lapply(sv_invs, function(sample) {
  # Set counter
  counter <<- counter + 1
  # Create track
  circos.genomicTrack(sample,
    panel.fun = function(region, value, ...) {
      circos.genomicLines(region,
                          value,
                          type = "h",
                          col = pal[counter],
                          cex = 0.05)
  },
  track.height = 0.07,
  bg.border = NA,
  ylim = c(0, max_len))
  
  # Add SV length y-axis label
  circos.yaxis(side = "right",
             at = c(2.5e5, max_len),
             labels.cex = 0.25*par("cex"),
             tick.length = 2
             )
  

  # Add SAMPLE y-axis label
  circos.text(2e6, 2.5e5,
              labels = names(sv_invs)[counter],
              sector.index = "chr1",
              cex = 0.4*par("cex"))
})


circos.clear()

dev.off()
knitr::include_graphics(basename(out_plot))

Final figure

final_svtype = ggdraw() +
  draw_image(here::here("plots", "sv_analysis", "20210224_sv_dels_lines.png"),
           x = 0, y = 0, width = 1, height = .7, scale = 1.12) +
  draw_plot(svtype_counts_plot,
            x = 0, y = .7, width = .5, height = .3) +
  draw_plot(svlen_counts_plot,
            x = .5, y = .7, width =.5, height = .3) +
  draw_plot_label(label = c("A", "B", "C"), size = 25,
                  x = c(0, .5, 0), y = c(1, 1, .7),color = "#4f0943")

final_svtype
ggsave(here::here("plots", "sv_analysis", "20210319_sv_main.png"),
       device = "png",
       dpi = 400,
       units = "cm",
       width = 30,
       height = 36)
LS0tCnRpdGxlOiAiU3RydWN0dXJhbCB2YXJpYW50cyIKYXV0aG9yOiAiSWFuIEJyZXR0ZWxsIgpkYXRlOiAnYHIgZm9ybWF0KFN5cy5EYXRlKCkpYCcKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCiNvdXRwdXQ6CiMgIGh0bWxfZG9jdW1lbnQ6CiMgICAgdG9jOiB0cnVlCiMgICAgdG9jX2Zsb2F0OiB0cnVlCiMgICAgZGV2OiAnc3ZnJwojICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQojICAgIGtlZXBfbWQ6IHRydWUKIyAgICBwYW5kb2NfYXJnczogLS1sdWEtZmlsdGVyPWNvbG9yLXRleHQubHVhCiMgICAgaGlnaGxpZ2h0OiBweWdtZW50cyAgCi0tLQoKRW1haWwgZnJvbSBUb20sIDE4IEphbnVhcnk6CgpbMS5de2NvbG9yPSJwdXJwbGUifSDigJxQb2xpc2jigJ0gU1YgY2FsbHMgdXNpbmcgSWxsdW1pbmEgZGF0YToKPGh0dHBzOi8vZ2l0aHViLmNvbS9zbWVocmluZ2VyL1NWaXBlcj4KClBsZWFzZSBleHBsb3JlIHRoZSBhYm92ZSAtIGdldCBpbnN0YWxsIGFuZCB0ZXN0ZWQuCgpOYW5vcG9yZSBWQ0YgZmlsZXM6CgoqIFtXSVRIIFNFUVVFTkNFU117Y29sb3I9InJlZCJ9OgpgbGwgL2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2Fkcmllbi9pbmRpZ2VuZS9hbmFseXNlcy9pbmRpZ2VuZV9uYW5vcG9yZV9ETkEvYnJhaW5fcnVuMi9ETkFfYW5hbHlzaXMvcmVzdWx0cy9TVi9zbmlmZmxlc19hbGxfT0xEL21lcmdlZC52Y2ZgCiogW1dJVEhPVVQgU0VRVUVOQ0VTXXtjb2xvcj0icmVkIn06YC9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9hZHJpZW4vaW5kaWdlbmUvYW5hbHlzZXMvaW5kaWdlbmVfbmFub3BvcmVfRE5BL2JyYWluX3J1bjIvRE5BX2FuYWx5c2lzL3Jlc3VsdHMvU1Yvc25pZmZsZXNfYWxsL21lcmdlZC52Y2ZgCgpgU1ZpcGVyYCBzYXlzOgo+VGhlIHZjZiBmaWxlIG11c3QgYmUgYSBzdHJ1Y3R1cmFsIHZhcmlhbnQgZm9ybWF0ICh0YWdzIGluc3RlYWQgb2Ygc2VxdWVuY2VzLCBlLmcuIDxERUw+KS4gQUxzbyB0aGUgSU5GTyBmaWVsZCBtdXN0IGluY2x1ZGUgdGhlIEVORCB0YWcsIGdpdmluZyB0aGUgZW5kIHBvc2l0aW9uIG9mIHRoZSB2YXJpYW50LCBhcyB3ZWxsIGFzIHRoZSBTVkxFTiB0YWcgaW4gY2FzZSBvZiBpbnNlcnRpb25zLgoKVGhlbiB3ZSBuZWVkIHRvIG1hcCBJbGx1bWluYSBJRCB0byB0aGUgTmFub3BvcmUgVkNGIGFuZCBmaWd1cmUgb3V0IGhvdyB0byBydW4gdGhlIHBvbGlzaGluZy4KCk9uY2UgZG9uZSB3ZSBuZWVkIHRvIHN1bW1hcmlzZSBhbmQgZGVzY3JpYmUgdGhlIFNW4oCZcyBhIGxpdHRsZSB3aXRoIHNvbWUgYW5ub3RhdGlvbnMgZXRjCi0gaSB3aWxsIG1ha2UgYSBzdGFydCB3aXRoIGRvaW5nIHRoaXMgcGFydCBhbmQgd2UgY2F0Y2h1cCBvbmNlIHlvdSBoYXZlIGxvb2tlZCBhdCB0aGUgcG9saXNoaW5nCgpbMi5de2NvbG9yPSJwdXJwbGUifSBjYXRjaHVwIHdpdGggSmFjayBvbiByZXBlYXRzIChib3RoIE1JS0sgcGFuZWwgYW5kIE5hbm9wb3JlIGFzc2VtYmxpZXMpLgotIGNyZWF0ZSBvbmUgcGxvdCBmb3IgZWFjaCBwYXBlcgoKMy4gRmVjdW5kaXR5IC0gaSB3aWxsIHNlbmQgeW91IHRoZSBkYXRhIGFuZCBhIGRlc2NyaXB0aW9uIG9mIHdoYXQgZXhhY3RseSBpdCBpcyBsYXRlciB0b2RheS4KLSB3ZSB3aWxsIG5lZWQgYSBnZW5lcmFsIGRlc2NyaXB0aW9uIG9mIHRoZSBkYXRhLCBkZXNjcmlwdGl2ZSBzdGF0cyBhbmQgYSBoZXJpdGFiaWxpdHkgZXN0aW1hdGUgLSBwbHVzIGEgc2luZ2xlIHBsb3Qgb3IgdGFibGUgKGZvciBNSUtLIHBhbmVsIHBhcGVyKQoKNC4gQWRkIHRvIHR4dCB3aXRoaW4gdGhlIHR3byBkb2N1bWVudHMgLSB3ZSBjYW4gY2F0Y2gtdXAgb24gdGhpcyBsYXRlciBpbiB0aGUgd2Vlay4KCiMgUG9saXNoIFNWIGNhbGxzIHdpdGggSWxsdW1pbmEgZGF0YQoKIyMgU2V0dXAKCldvcmtpbmcgZGlyZWN0b3J5IG9uIEVCSSBjbHVzdGVyOiBgL2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2lhbi9taWtrX3BhcGVyL21pa2tfZ2Vub21lL3N2X2FuYWx5c2lzYApHaXRIdWIgcmVwbzogPGh0dHBzOi8vZ2l0aHViLmNvbS9icmV0dGVsbGViaS9taWtrX2dlbm9tZT4KCiMjIyBgY29uZGFgIGVudnMKCiMjIyMgYHN2X2VudmAKCmBgYHtiYXNoLCBldmFsID0gRn0KIyBNYWtlIGNvbmRhIGVudgptYW1iYSBjcmVhdGUgLW4gc3ZfZW52CmNvbmRhIGFjdGl2YXRlIHN2X2VudgojIEluc3RhbGwgcGFja2FnZXMKbWFtYmEgaW5zdGFsbCAtYyBiaW9jb25kYSBiY2Z0b29scyBzbmlmZmxlcwptYW1iYSBpbnN0YWxsIC1jIGNvbmRhLWZvcmdlIHItYmFzZSByLXRpZHl2ZXJzZQojIEV4cG9ydCB0byBmaWxlCmNvbmRhIGVudiBleHBvcnQgPiBlbnZzL3N2X2Vudi9zdl9lbnYueWFtbApgYGAKCiMjIyMgYGJhc2VSYAoKYGBge2Jhc2gsIGV2YWwgPSBGfQojIEFjdGl2YXRlCmNvbmRhIGFjdGl2YXRlIGJhc2VSCiMgRXhwb3J0CmNvbmRhIGVudiBleHBvcnQgPiBlbnZzL2Jhc2VSL2Jhc2VSLnlhbWwKYGBgCgojIyMgYHJlbnZgCgpgYGB7ciwgZXZhbCA9IEZ9CiMgSW5pdGlhdGUKcmVudjo6aW5pdCgpCiMgU25hcHNob3QKcmVudjo6c25hcHNob3QoKQojIFJlc3RvcmUKcmVudjo6cmVzdG9yZSgpCmBgYAoKIyMjIyBTb3VyY2UKCmBgYHtyLCBtZXNzYWdlID0gRn0KbGlicmFyeShoZXJlKQpzb3VyY2UoaGVyZTo6aGVyZSgiY29kZSIsICJzY3JpcHRzIiwgInN2X2FuYWx5c2lzIiwgInNvdXJjZS5SIikpCmBgYAoKIyMjIE5hbm9wb3JlIFZDRgoKYC9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9hZHJpZW4vYW5hbHlzZXMvbWVkYWthX0ROQV9wcm9tZXRoaW9uL2JyYWluX3J1bjIvRE5BX2FuYWx5c2lzL3Jlc3VsdHMvU1Yvc25pZmZsZXNfYWxsL21lcmdlZC52Y2ZgCgpDcmVhdGVkIHdpdGg6CmBgYHtiYXNoLCBldmFsID0gRn0KIyBGaXJzdCB1c2VkOgpzbmlmZmxlcyBcCiAgLS1taW5fc3VwcG9ydCAzIFwKICAtLW1heF9udW1fc3BsaXRzIDcgXAogIC0tbWF4X2Rpc3RhbmNlIDEwMDAgXAogIC0tbWluX2xlbmd0aCA1MCBcCiAgLS1taW5tYXBwaW5nX3F1YWwgMjAgXAogIC0tbWluX3NlcV9zaXplIDEwMDAgXAogIC0tYWxsZWxlZnJlcSAwLjEgXAogIC10IHt0aHJlYWRzfSBcCiAgLW0ge2lucHV0X2JhbX0gXAogIC12IHtvdXRwdXRfdmNmfQoKYGBgCgpBZHJpZW46Cj5UaGVuIEkgZmlsdGVyZWQgYW5kIG1lcmdlZCBhbGwgdGhlIHZhcmlhbnRzIGZyb20gdGhlIGRpZmZlcmVudCBzYW1wbGVzIHRvZ2V0aGVyIHdpdGggc3Vydml2b3IgYW5kIHJlY2FsbGVkIHZhcmlhbnRzIGEgc2Vjb25kIHRpbWUgaW4gZm9yY2VkIG1vZGUgdXNpbmcgdGhlIG1lcmdlZCBzZXQgd2l0aCBzbmlmZmxlcyBhZ2FpbiB1c2luZyB0aGUgc2FtZSBvcHRpb25zLgoKIyMjIyBDb3B5IHRvIHdvcmtpbmcgZGlyZWN0b3J5CgpgYGB7YmFzaCwgZXZhbCA9IEZ9CiMgV2l0aCBzZXF1ZW5jZXMKbmFub19yYXc9L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2Fkcmllbi9pbmRpZ2VuZS9hbmFseXNlcy9pbmRpZ2VuZV9uYW5vcG9yZV9ETkEvYnJhaW5fcnVuMi9ETkFfYW5hbHlzaXMvcmVzdWx0cy9TVi9zbmlmZmxlc19hbGxfT0xEL21lcmdlZC52Y2YKb3V0X3BhdGg9Li4vc3ZfYW5hbHlzaXMvdmNmcy9vbnRfcmF3X3dpdGhfc2VxLnZjZgojIyBDb3B5CmNwICRuYW5vX3JhdyAkb3V0X3BhdGgKCiMgV2l0aG91dCBzZXF1ZW5jZXMKbmFub19yYXc9L2hwcy9yZXNlYXJjaDEvYmlybmV5L3VzZXJzL2Fkcmllbi9pbmRpZ2VuZS9hbmFseXNlcy9pbmRpZ2VuZV9uYW5vcG9yZV9ETkEvYnJhaW5fcnVuMi9ETkFfYW5hbHlzaXMvcmVzdWx0cy9TVi9zbmlmZmxlc19hbGwvbWVyZ2VkLnZjZgpvdXRfcGF0aD0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXcudmNmCiMjIENvcHkKY3AgJG5hbm9fcmF3ICRvdXRfcGF0aApgYGAKCiMjIyMgUmVuYW1lIHNhbXBsZXMKCiMjIyMjIFdpdGggc2VxdWVuY2VzCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmNvbmRhIGFjdGl2YXRlIHN2X2VudgoKaW5fdmNmPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd193aXRoX3NlcS52Y2YKc2FtcGxlX2ZpbGU9ZGF0YS9zdl9hbmFseXNpcy8yMDIxMDIwNV9vbnRfcmF3X3NhbXBsZXNfZmlsZS50eHQKb3V0X3ZjZj0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXdfd2l0aF9zZXFfcmVoZWFkLnZjZgoKIyBNYWtlIHNhbXBsZXMga2V5IGZpbGUKYmNmdG9vbHMgcXVlcnkgLWwgJGluX3ZjZiBcCiAgPiB0bXAxCmN1dCAtZjQgLWQnLycgdG1wMSB8IGN1dCAtZjEgLWQnXycgXAogID4gdG1wMgpwYXN0ZSAtZCcgJyB0bXAxIHRtcDIgPiAkc2FtcGxlX2ZpbGUKcm0gdG1wMSB0bXAyCgojIFJlbmFtZSBWQ0YKYmNmdG9vbHMgcmVoZWFkZXIgXAogIC0tc2FtcGxlcyAkc2FtcGxlX2ZpbGUgXAogIC0tb3V0cHV0ICRvdXRfdmNmIFwKICAkaW5fdmNmCmBgYAoKIyMjIyMgV2l0aG91dCBzZXF1ZW5jZXMKCmBgYHtiYXNoLCBldmFsID0gRn0KY29uZGEgYWN0aXZhdGUgc3ZfZW52Cgppbl92Y2Y9Li4vc3ZfYW5hbHlzaXMvdmNmcy9vbnRfcmF3LnZjZgpzYW1wbGVfZmlsZT1kYXRhL3N2X2FuYWx5c2lzLzIwMjEwMjEyX29udF9yYXdfc2FtcGxlc19maWxlLnR4dApvdXRfdmNmPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd19yZWhlYWQudmNmCgojIE1ha2Ugc2FtcGxlcyBrZXkgZmlsZQpiY2Z0b29scyBxdWVyeSAtbCAkaW5fdmNmIFwKICA+IHRtcDEKY3V0IC1mNCAtZCcvJyB0bXAxIHwgY3V0IC1mMSAtZCdfJyBcCiAgPiB0bXAyCnBhc3RlIC1kJyAnIHRtcDEgdG1wMiA+ICRzYW1wbGVfZmlsZQpybSB0bXAxIHRtcDIKCiMgUmVuYW1lIFZDRgpiY2Z0b29scyByZWhlYWRlciBcCiAgLS1zYW1wbGVzICRzYW1wbGVfZmlsZSBcCiAgLS1vdXRwdXQgJG91dF92Y2YgXAogICRpbl92Y2YKYGBgCgojIyMjIEdldCBzdGF0cwoKIyMjIyMgV2l0aCBzZXF1ZW5jZXMKCmBgYHtiYXNoLCBldmFsID0gRn0KY29uZGEgYWN0aXZhdGUgc3ZfbWlrawoKaW5fdmNmPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd193aXRoX3NlcS52Y2YKc3RhdHNfb3V0PS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd193aXRoX3NlcS5zdGF0cwoKIyBHZXQgc3RhdHMKYmNmdG9vbHMgc3RhdHMgXAogICRpbl92Y2YgXAogICAgPiAkc3RhdHNfb3V0CmBgYAoKIyMjIyMgV2l0aG91dCBzZXF1ZW5jZXMKCmBgYHtiYXNoLCBldmFsID0gRn0KY29uZGEgYWN0aXZhdGUgc3ZfbWlrawoKaW5fdmNmPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhdy52Y2YKc3RhdHNfb3V0PS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhdy5zdGF0cwoKIyBHZXQgc3RhdHMKYmNmdG9vbHMgc3RhdHMgXAogICRpbl92Y2YgXAogICAgPiAkc3RhdHNfb3V0CmBgYAoKIyMjIyBTcGxpdCBwZXIgc2FtcGxlCgojIyMjIyBXaXRoIHNlcXVlbmNlcwoKYGBge2Jhc2h9CmNvbmRhIGFjdGl2YXRlIHN2X21pa2sKCmluX3ZjZj0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXdfd2l0aF9zZXFfcmVoZWFkLnZjZgpvdXRfZGlyPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd193aXRoX3NlcV9yZWhlYWRfcGVyX3NhbXBsZQoKbWtkaXIgLXAgJG91dF9kaXIKCiMgU3BsaXQgYnkgc2FtcGxlCmJjZnRvb2xzICtzcGxpdCBcCiAgJGluX3ZjZiBcCiAgLS1vdXRwdXQgJG91dF9kaXIKYGBgCgojIyMjIyBXaXRob3V0IHNlcXVlbmNlcwoKYGBge2Jhc2h9CmNvbmRhIGFjdGl2YXRlIHN2X21pa2sKCmluX3ZjZj0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXdfcmVoZWFkLnZjZgpvdXRfZGlyPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd19yZWhlYWRfcGVyX3NhbXBsZQoKbWtkaXIgLXAgJG91dF9kaXIKCiMgU3BsaXQgYnkgc2FtcGxlCmJjZnRvb2xzICtzcGxpdCBcCiAgJGluX3ZjZiBcCiAgLS1vdXRwdXQgJG91dF9kaXIKYGBgCgojIyMgSWxsdW1pbmEgVkNGCgojIyMjIENvcHkgdG8gd29ya2luZyBkaXJlY3RvcnkKCmBgYHtiYXNoLCBldmFsID0gRn0KY29uZGEgYWN0aXZhdGUgc3ZfZW52Cgppbl92Y2Y9L25mcy9yZXNlYXJjaDEvYmlybmV5L3Byb2plY3RzL21lZGFrYS9pbmJyZWRfcGFuZWwvbWVkYWthLWFsaWdubWVudHMtcmVsZWFzZS05NC92Y2YvbWVkYWthX2luYnJlZF9wYW5lbF9lbnNlbWJsX25ld19yZWZlcmVuY2VfcmVsZWFzZV85NC52Y2YKb3V0X3ZjZj0uLi9zdl9hbmFseXNpcy92Y2ZzL2lsbF9yYXcudmNmLmd6CgojIENvbXByZXNzIGFuZCBjb3B5CmJzdWIgXAogIC1NIDMwMDAwIFwKICAtbyAuLi9sb2cvMjAyMTAyMDhfY29tcF9pbGwub3V0IFwKICAtZSAuLi9sb2cvMjAyMTAyMDhfY29tcF9pbGwuZXJyIFwKYnN1YiAtSXMgYmFzaCBcCiAgIiIiCiAgY29uZGEgYWN0aXZhdGUgc3ZfZW52IDsKICBiY2Z0b29scyB2aWV3IFwKICAgIC0tb3V0cHV0LXR5cGUgeiBcCiAgICAtLW91dHB1dCAkb3V0X3ZjZiBcCiAgICAkaW5fdmNmCiAgIiIiICAKYGBgCgojIyMjIFJlbmFtZSBhbmQgZmlsdGVyIGZvciBPTlQgc2FtcGxlcwoKIyMjIyMgUHVsbCBvdXQgSURzIGZvciByZWxldmFudCBzYW1wbGVzCgpgYGB7ciwgZXZhbCA9IEZ9Cm9udF9zYW1wbGVzID0gaGVyZTo6aGVyZSgiZGF0YSIsICJzdl9hbmFseXNpcyIsICIyMDIxMDIwNV9vbnRfcmF3X3NhbXBsZXNfZmlsZS50eHQiKQppbGxfc2FtcGxlcyA9IGhlcmU6OmhlcmUoImRhdGEiLCIyMDIwMDIwNl9jcmFtX2lkX3RvX2xpbmVfaWQudHh0IikKb3V0X2ZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgInN2X2FuYWx5c2lzIiwgIjIwMjEwMjA1X2lsbF9rZXlfb250X3NhbXBsZXMudHh0IikKb3V0X3NhbXBsZXMgPSBoZXJlOjpoZXJlKCJkYXRhIiwgInN2X2FuYWx5c2lzIiwgIjIwMjEwMjA1X29udF9zYW1wbGVzX29ubHkudHh0IikKCiMgUmVhZCBpbiB0YWJsZXMKCm9udF9rZXkgPSByZWFkLnRhYmxlKG9udF9zYW1wbGVzKQppbGxfa2V5ID0gcmVhZC50YWJsZShpbGxfc2FtcGxlcywgY29tbWVudC5jaGFyID0gIlwiIiwgaGVhZGVyID0gVCkgJT4lIAogIGRwbHlyOjptdXRhdGUobGluZSA9IGdzdWIoIl8iLCAiLSIsIGxpbmUpKQoKIyBGaW5kIG1hdGNoZXMKb3V0ID0gaWxsX2tleVtpbGxfa2V5JGxpbmUgJWluJSBvbnRfa2V5JFYyLCBdCgojIFdyaXRlIHRvIGZpbGVzCiMjIEtleSBmaWxlCnJlYWRyOjp3cml0ZV9kZWxpbShvdXQsIG91dF9maWxlLCBkZWxpbSA9ICIgIiwgY29sX25hbWVzID0gRikKIyMgSnVzdCBzYW1wbGVzCnJlYWRyOjp3cml0ZV9saW5lcyhvdXQkY3JhbV9maWxlLCBvdXRfc2FtcGxlcykKYGBgCgojIyMjIyBSZW5hbWUgYW5kIGZpbHRlcgoKYGBge2Jhc2gsIGV2YWwgPSBGfQppbl92Y2Y9Li4vc3ZfYW5hbHlzaXMvdmNmcy9pbGxfcmF3LnZjZi5negpzYW1wbGVzX2ZpbGU9ZGF0YS9zdl9hbmFseXNpcy8yMDIxMDIwNV9vbnRfc2FtcGxlc19vbmx5LnR4dApzYW1wbGVzX2tleT1kYXRhL3N2X2FuYWx5c2lzLzIwMjEwMjA1X2lsbF9rZXlfb250X3NhbXBsZXMudHh0Cm91dF92Y2Y9Li4vc3ZfYW5hbHlzaXMvdmNmcy9pbGxfcmF3X3JlaGVhZC52Y2YuZ3oKb3V0X2Rpcj0uLi9zdl9hbmFseXNpcy92Y2ZzL2lsbF9yYXdfcmVoZWFkX3Blcl9zYW1wbGUKCm1rZGlyIC1wICRvdXRfZGlyCgojIEZpbHRlciBmb3IgdGFyZ2V0IHNhbXBsZXMgYW5kIHJlaGVhZApiY2Z0b29scyB2aWV3IFwKICAtLXNhbXBsZXMtZmlsZSAkc2FtcGxlc19maWxlIFwKICAtLW91dHB1dC10eXBlIHUgXAogICRpbl92Y2YgfFwKICAgIGJjZnRvb2xzIHJlaGVhZGVyIFwKICAgICAgLS1zYW1wbGVzICRzYW1wbGVzX2tleSBcCiAgICAgIC0tb3V0cHV0ICRvdXRfdmNmCgojIFNwbGl0IGJ5IHNhbXBsZQpiY2Z0b29scyArc3BsaXQgXAogICRvdXRfdmNmIFwKICAtLW91dHB1dCAkb3V0X2RpcgpgYGAKCiMjIyBCQU1zCgojIyMjIElsbHVtaW5hIGAuYmFtYCBmaWxlcwoKQ29weSB0byBsb2NhbC4KCmBgYHtiYXNofQpzYW1wbGVfa2V5PWRhdGEvc3ZfYW5hbHlzaXMvMjAyMTAyMDVfaWxsX2tleV9vbnRfc2FtcGxlcy50eHQKaWxsX2JhbV9kaXI9L25mcy9yZXNlYXJjaDEvYmlybmV5L3Byb2plY3RzL21lZGFrYS9pbmJyZWRfcGFuZWwvbWVkYWthLWFsaWdubWVudHMtcmVsZWFzZS05NC9iYW0Kb3V0X2Rpcj0uLi9zdl9hbmFseXNpcy9iYW1zCgpta2RpciAtcCAkb3V0X2RpciAKCiMgQ29weSBvdmVyCmZvciBzYW1wbGUgaW4gJChjdXQgLWYxIC1kJyAnICRzYW1wbGVfa2V5ICkgOyBkbwogIGNwICRpbGxfYmFtX2Rpci8kc2FtcGxlLmJhaSAkb3V0X2RpciA7CmRvbmUgIAoKIyBTVmlwZXIgbmVlZHMgYmFtcyBpbiAuYmFtLmJhaSBmb3JtYXQuIE9yaWdpbmFsIHtzYW1wbGV9LmJhaSBmaWxlcyBuZWVkIHRvIGJlIGNvcGllZCB0byB7c2FtcGxlfS5iYW0uYmFpCmZvciBmaWxlIGluICQoIGZpbmQgJG91dF9kaXIvKi5iYWkgKSA7IGRvCiAgbmV3X2ZpbGVuYW1lPSQoIGVjaG8gJGZpbGUgfCBzZWQgJ3MvLmJhaS8uYmFtLmJhaS9nJyApIDsKICBtdiAkZmlsZSAkbmV3X2ZpbGVuYW1lIDsKZG9uZQpgYGAKCiMjIyMgTmFub3BvcmUgYC5iYW1gIGZpbGVzCgpTaXQgaGVyZTogYC9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9hZHJpZW4vaW5kaWdlbmUvYW5hbHlzZXMvaW5kaWdlbmVfbmFub3BvcmVfRE5BL2JyYWluX3J1bjIvRE5BX2FuYWx5c2lzL3Jlc3VsdHMvU1YvbmdtbHJfYWxpZ25tZW50cy9gCgojIyBQb2xpc2ggTmFub3BvcmUgcmVhZHMgd2l0aCBgU1ZpcGVyYAoKIyMjIENyZWF0ZSBTaW5ndWxhcml0eSBjb250YWluZXIKYGBge2Jhc2gsIGV2YWwgPSBGfQptb2R1bGUgbG9hZCBzaW5ndWxhcml0eQoKIyBCdWlsZApzaW5ndWxhcml0eSBidWlsZCBcCiAgLS1yZW1vdGUgLi4vc2luZ19jb250cy9zdmlwZXIuc2lmIFwKICBlbnZzL3N2aXBlci8yMDIxMDIwNF9zdmlwZXIuZGVmCiAgCiMgT3BlbiBpbnRlcmFjdGl2ZSBzaGVsbApic3ViIC1JcyAic2luZ3VsYXJpdHkgc2hlbGwgLi4vc2luZ19jb250cy9zdmlwZXIuc2lmIgojIFdvcmtzISAKYGBgCgojIyMgVGVzdAoKYGBge2Jhc2gsIGV2YWwgPSBGfQojIExvYWQgc2luZ3VsYXJpdHkKbW9kdWxlIGxvYWQgc2luZ3VsYXJpdHkKIyBQdWxsIGltYWdlIGJ1aWx0IHdpdGggYGVudnMvc3ZpcGVyLzIwMjEwMjA0X3N2aXBlci5kZWZgCmJzdWIgLU0gMzAwMDAgLW4gNCAtSXMgInNpbmd1bGFyaXR5IHNoZWxsIC4uL3NpbmdfY29udHMvc3ZpcGVyLnNpZiIKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgVmFyaWFibGVzCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIENvbnRhaW5lcgpjb250YWluZXI9Li4vc2luZ19jb250cy9zdmlwZXIuc2lmCiMjIFNhbXBsZQpzYW1wbGU9MTEtMQpzYW1wbGVfa2V5PWRhdGEvc3ZfYW5hbHlzaXMvMjAyMTAyMDVfaWxsX2tleV9vbnRfc2FtcGxlcy50eHQKIyMgVkNGIHRvIHBvbGlzaApvbnRfdmNmPS4uL3N2X2FuYWx5c2lzL3ZjZnMvb250X3Jhd19yZWhlYWRfcGVyX3NhbXBsZS8kc2FtcGxlLnZjZgojIyBJbGx1bWluYSBCQU0KaWxsX2NyYW1faWQ9JChncmVwICRzYW1wbGUgJHNhbXBsZV9rZXkgfCBjdXQgLWYxIC1kJyAnKQppbGxfYmFtX2Rpcj0uLi9zdl9hbmFseXNpcy9iYW1zCmlsbF9iYW09JGlsbF9iYW1fZGlyLyRpbGxfY3JhbV9pZC5iYW0KIyMgTmFub3BvcmUgQkFNCm9udF9iYW1fZGlyPS9ocHMvcmVzZWFyY2gxL2Jpcm5leS91c2Vycy9hZHJpZW4vaW5kaWdlbmUvYW5hbHlzZXMvaW5kaWdlbmVfbmFub3BvcmVfRE5BL2JyYWluX3J1bjIvRE5BX2FuYWx5c2lzL3Jlc3VsdHMvU1YvbmdtbHJfYWxpZ25tZW50cwpvbnRfYmFtPSQoZmluZCAkb250X2JhbV9kaXIvJHNhbXBsZSouYmFtKQojIyBSZWZlcmVuY2UKcmVmPS4uL3JlZnMvT3J5emlhc19sYXRpcGVzLkFTTTIyMzQ2N3YxLmRuYS50b3BsZXZlbC5mYQojIyBPdXRwdXQgZGlyZWN0b3J5Cm91dF9kaXI9Li4vc3ZfYW5hbHlzaXMvdmNmcy9zdmlwZXIKbWtkaXIgLXAgJG91dF9kaXIKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgVEVTVCBjYWxsIHN2aXBlciAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKc3ZpcGVyIFwKICAtLWNhbmRpZGF0ZS12Y2YgJG9udF92Y2YgXAogIC0tc2hvcnQtcmVhZC1iYW0gJGlsbF9iYW0gXAogIC0tbG9uZy1yZWFkLWJhbSAkb250X2JhbSBcCiAgLS1yZWZlcmVuY2UgJHJlZiBcCiAgLS1vdXRwdXQtcHJlZml4ICRvdXRfZGlyLyRzYW1wbGUKCmBgYAoKIyMjIFRydWUKCmBgYHtiYXNoLCBldmFsID0gRn0KIyBMb2FkIHNpbmd1bGFyaXR5Cm1vZHVsZSBsb2FkIHNpbmd1bGFyaXR5CiMgUHVsbCBpbWFnZSBidWlsdCB3aXRoIGBlbnZzL3N2aXBlci8yMDIxMDIwNF9zdmlwZXIuZGVmYApic3ViIC1NIDMwMDAwIC1uIDQgLUlzICJzaW5ndWxhcml0eSBzaGVsbCAuLi9zaW5nX2NvbnRzL3N2aXBlci5zaWYiCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFZhcmlhYmxlcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyBTYW1wbGUKc2FtcGxlPTExLTEKc2FtcGxlX2tleT1kYXRhL3N2X2FuYWx5c2lzLzIwMjEwMjA1X2lsbF9rZXlfb250X3NhbXBsZXMudHh0CiMjIFZDRiB0byBwb2xpc2gKb250X3ZjZj0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXdfcmVoZWFkX3Blcl9zYW1wbGUvJHNhbXBsZS52Y2YKIyMgSWxsdW1pbmEgQkFNCmlsbF9jcmFtX2lkPSQoZ3JlcCAkc2FtcGxlICRzYW1wbGVfa2V5IHwgY3V0IC1mMSAtZCcgJykKaWxsX2JhbV9kaXI9Li4vc3ZfYW5hbHlzaXMvYmFtcwppbGxfYmFtPSRpbGxfYmFtX2Rpci8kaWxsX2NyYW1faWQuYmFtCiMjIE5hbm9wb3JlIEJBTQpvbnRfYmFtX2Rpcj0vaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvYWRyaWVuL2luZGlnZW5lL2FuYWx5c2VzL2luZGlnZW5lX25hbm9wb3JlX0ROQS9icmFpbl9ydW4yL0ROQV9hbmFseXNpcy9yZXN1bHRzL1NWL25nbWxyX2FsaWdubWVudHMKb250X2JhbT0kKGZpbmQgJG9udF9iYW1fZGlyLyRzYW1wbGUqLmJhbSkKIyMgUmVmZXJlbmNlCnJlZj0uLi9yZWZzL09yeXppYXNfbGF0aXBlcy5BU00yMjM0Njd2MS5kbmEudG9wbGV2ZWwuZmEKIyMgQ29udGFpbmVyCmNvbnRhaW5lcj0uLi9zaW5nX2NvbnRzL3N2aXBlci5zaWYKIyMgT3V0cHV0IGRpcmVjdG9yeQpvdXRfZGlyPS4uL3N2X2FuYWx5c2lzL3ZjZnMvc3ZpcGVyCm1rZGlyIC1wICRvdXRfZGlyCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFRFU1QgY2FsbCBzdmlwZXIgCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnN2aXBlciBcCiAgLS1jYW5kaWRhdGUtdmNmICRvbnRfdmNmIFwKICAtLXNob3J0LXJlYWQtYmFtICRpbGxfYmFtIFwKICAtLWxvbmctcmVhZC1iYW0gJG9udF9iYW0gXAogIC0tcmVmZXJlbmNlICRyZWYgXAogIC0tb3V0cHV0LXByZWZpeCAkb3V0X2Rpci8kc2FtcGxlCiAgCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgVFJVRSBjYWxsIHN2aXBlciAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgCm1vZHVsZSBsb2FkIHNpbmd1bGFyaXR5CgojIEdsb2JhbCB2YXJpYWJsZXMKIyMgU2FtcGxlIGtleQpzYW1wbGVfa2V5PWRhdGEvc3ZfYW5hbHlzaXMvMjAyMTAyMDVfaWxsX2tleV9vbnRfc2FtcGxlcy50eHQKIyMgQkFNIGRpcnMKaWxsX2JhbV9kaXI9Li4vc3ZfYW5hbHlzaXMvYmFtcwpvbnRfYmFtX2Rpcj0vaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvYWRyaWVuL2luZGlnZW5lL2FuYWx5c2VzL2luZGlnZW5lX25hbm9wb3JlX0ROQS9icmFpbl9ydW4yL0ROQV9hbmFseXNpcy9yZXN1bHRzL1NWL25nbWxyX2FsaWdubWVudHMKIyMgUmVmZXJlbmNlCnJlZj0uLi9yZWZzL09yeXppYXNfbGF0aXBlcy5BU00yMjM0Njd2MS5kbmEudG9wbGV2ZWwuZmEKIyMgQ29udGFpbmVyCmNvbnRhaW5lcj0uLi9zaW5nX2NvbnRzL3N2aXBlci5zaWYKIyMgT3V0cHV0IGRpcmVjdG9yeQpvdXRfZGlyPS4uL3N2X2FuYWx5c2lzL3ZjZnMvc3ZpcGVyCm1rZGlyIC1wICRvdXRfZGlyCgpmb3Igc2FtcGxlIGluICQoY3V0IC1mMiAtZCcgJyAkc2FtcGxlX2tleSB8IHRhaWwgLW4rMiApIDsgZG8KICAjIFNldCB2YXJpYWJsZXMKICAKICAjIyBWQ0YgdG8gcG9saXNoCiAgb250X3ZjZj0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXdfcmVoZWFkX3Blcl9zYW1wbGUvJHNhbXBsZS52Y2YKICAjIyBJbGx1bWluYSBCQU0KICBpbGxfY3JhbV9pZD0kKGdyZXAgIiAkc2FtcGxlIiAkc2FtcGxlX2tleSB8IGN1dCAtZjEgLWQnICcpCiAgaWxsX2JhbT0kaWxsX2JhbV9kaXIvJGlsbF9jcmFtX2lkLmJhbQogICMjIE5hbm9wb3JlIEJBTQogIG9udF9iYW09JChmaW5kICRvbnRfYmFtX2Rpci8kc2FtcGxlKi5iYW0pCgogICMgUnVuIFNWaXBlcgogIGJzdWIgXAogICAgLU0gMzAwMDAgXAogICAgLW4gMTYgXAogICAgLW8gLi4vbG9nLzIwMjEwMjEyX3N2aXBlcl8kc2FtcGxlLm91dCBcCiAgICAtZSAuLi9sb2cvMjAyMTAyMTJfc3ZpcGVyXyRzYW1wbGUuZXJyIFwKICAgICIiIgogICAgc2luZ3VsYXJpdHkgZXhlYyAkY29udGFpbmVyIFwKICAgICAgc3ZpcGVyIFwKICAgICAgICAtLWNhbmRpZGF0ZS12Y2YgJG9udF92Y2YgXAogICAgICAgIC0tc2hvcnQtcmVhZC1iYW0gJGlsbF9iYW0gXAogICAgICAgIC0tbG9uZy1yZWFkLWJhbSAkb250X2JhbSBcCiAgICAgICAgLS1yZWZlcmVuY2UgJHJlZiBcCiAgICAgICAgLS1vdXRwdXQtcHJlZml4ICRvdXRfZGlyLyRzYW1wbGUKICAgICIiIgpkb25lCgojIDQtMiBhbmQgNy0yIGZhaWxlZCB3aXRoIG5vIGVycm9yIG1lc3NhZ2UKYGBgCgojIyMgTWVyZ2UKCmBgYHtiYXNoLCBldmFsID0gRn0KIyBHZXQgbGlzdCBvZiB2Y2YgcGF0aHMKaW5fZGlyPS4uL3N2X2FuYWx5c2lzL3ZjZnMvc3ZpcGVyCm91dF9kaXI9JGluX2Rpci9tZXJnZWQKbWtkaXIgLXAgJG91dF9kaXIKaW5fdmNmcz0kKGZpbmQgJGluX2Rpci8qLnZjZiB8IHRyICdcbicgJyAnKQoKYmNmdG9vbHMgbWVyZ2UgXAogIC0tb3V0cHV0ICRvdXRfZGlyL2FsbC52Y2ZcCiAgJGluX3ZjZnMKICAKIyBSZXF1aXJlcyB0aGVtIHRvIGJlIGJnemlwcGVkCgojIFRyeSB3aXRoIFBpY2FyZAppbl9kaXI9Li4vc3ZfYW5hbHlzaXMvdmNmcy9zdmlwZXIKb3V0X2Rpcj0kaW5fZGlyL21lcmdlZApta2RpciAtcCAkb3V0X2RpcgpmaW5kICRpbl9kaXIvKi52Y2YgPiB0bXAubGlzdAoKcGljYXJkIE1lcmdlVmNmcyBcCiAgST10bXAubGlzdCBcCiAgTz0kb3V0X2Rpci9tZXJnZWQudmNmLmd6CgpybSB0bXAubGlzdAojRXhjZXB0aW9uIGluIHRocmVhZCAibWFpbiIgamF2YS5sYW5nLklsbGVnYWxBcmd1bWVudEV4Y2VwdGlvbjogSW5wdXQgZmlsZSAvaHBzL3Jlc2VhcmNoMS9iaXJuZXkvdXNlcnMvaWFuL21pa2tfcGFwZXIvbWlra19nZW5vbWUvLi4vc3ZfYW5hbHlzaXMvdmNmcy9zdmlwZXIvMTE3LTIudmNmIGhhcyBzYW1wbGUgZW50cmllcyB0aGF0IGRvbid0IG1hdGNoIHRoZSBvdGhlciBmaWxlcy4KYGBgCgo8IS0tCiMjIyBUcnkgYFNVUlZJVk9SYAoKPGh0dHBzOi8vZ2l0aHViLmNvbS9mcml0enNlZGxhemVjay9TVVJWSVZPUj4KCmBgYHtiYXNoLCBldmFsID0gRn0KbW9kdWxlIGxvYWQgc2luZ3VsYXJpdHkKCiMgQnVpbGQKc2luZ3VsYXJpdHkgYnVpbGQgXAogIC0tcmVtb3RlIC4uL3NpbmdfY29udHMvc3Vydml2b3Iuc2lmIFwKICBlbnZzL3N1cnZpdm9yLzIwMjEwMjE3X3N1cnZpdm9yLmRlZgogIAojIE9wZW4gaW50ZXJhY3RpdmUgc2hlbGwKYnN1YiAtSXMgInNpbmd1bGFyaXR5IHNoZWxsIC4uL3NpbmdfY29udHMvc3Vydml2b3Iuc2lmIgojIFdvcmtzISAKYGBgCgotLT4KCiMjIyBHZXQgZGF0YSBmcm9tIGBTVmlwZXJgCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmluX2Rpcj0uLi9zdl9hbmFseXNpcy92Y2ZzL3N2aXBlcgpvdXRfZGlyPWRhdGEvc3ZfYW5hbHlzaXMvMjAyMTAyMTdfc3ZpcGVyX2ZpbHRlcl9wYXNzCgpta2RpciAtcCAkb3V0X2RpcgoKZm9yIGluX3ZjZiBpbiAkKGZpbmQgJGluX2Rpci8qdmNmKSA7IGRvCiAgc2FtcGxlPSQoYmFzZW5hbWUgJGluX3ZjZiB8IGN1dCAtZjEgLWQnLicgKSA7CiAgYmNmdG9vbHMgcXVlcnkgXAogICAgLS1pbmNsdWRlICdGSUxURVI9IlBBU1MiJyBcCiAgICAtLWV4Y2x1ZGUgJ0dUfiJcLiInIFwKICAgIC0tZm9ybWF0ICclQ0hST00sJVBPUywlQUxULCVJTkZPL1NWTEVOLCVJTkZPL1NWVFlQRSwlSU5GTy9DSFIyLCVJTkZPL0VORCxbJUdUXSxbJUxOXSxbJVNUXVxuJyBcCiAgLS1vdXRwdXQgJG91dF9kaXIvJHNhbXBsZS5jc3YgXAogICRpbl92Y2YgOwpkb25lCmBgYAoKIyMjIEdldCBkYXRhIGZyb20gb3JpZ2luYWwgVkNGCgpgYGB7YmFzaCwgZXZhbCA9IEZ9CmluX2Rpcj0uLi9zdl9hbmFseXNpcy92Y2ZzL29udF9yYXdfcmVoZWFkX3Blcl9zYW1wbGUKb3V0X2Rpcj1kYXRhL3N2X2FuYWx5c2lzLzIwMjEwMjE3X3Jhd19vbnRfZmlsdGVyX3Bhc3MKCm1rZGlyIC1wICRvdXRfZGlyCgpmb3IgaW5fdmNmIGluICQoZmluZCAkaW5fZGlyLyp2Y2YpIDsgZG8KICBzYW1wbGU9JChiYXNlbmFtZSAkaW5fdmNmIHwgY3V0IC1mMSAtZCcuJyApIDsKICBiY2Z0b29scyBxdWVyeSBcCiAgICAtLWluY2x1ZGUgJ0ZJTFRFUj0iUEFTUyInIFwKICAgIC0tZXhjbHVkZSAnR1R+IlwuIicgXAogICAgLS1mb3JtYXQgJyVDSFJPTSwlUE9TLCVBTFQsJUlORk8vU1ZMRU4sJUlORk8vU1ZUWVBFLCVJTkZPL0NIUjIsJUlORk8vRU5ELFslR1RdLFslTE5dLFslU1RdXG4nIFwKICAtLW91dHB1dCAkb3V0X2Rpci8kc2FtcGxlLmNzdiBcCiAgJGluX3ZjZiA7CmRvbmUKYGBgCgojIyMgR2V0IHBvbGlzaCBzdGF0cyAKCmBgYHtiYXNoLCBldmFsID0gRn0KaW5fZGlyPS4uL3N2X2FuYWx5c2lzL3ZjZnMvc3ZpcGVyCm91dF9kaXI9ZGF0YS9zdl9hbmFseXNpcy8yMDIxMDIyNl9wb2xpc2hfc3RhdHMKCm1rZGlyIC1wICRvdXRfZGlyCgpmb3IgaW5fdmNmIGluICQoZmluZCAkaW5fZGlyLyp2Y2YpIDsgZG8KICBzYW1wbGU9JChiYXNlbmFtZSAkaW5fdmNmIHwgY3V0IC1mMSAtZCcuJyApIDsKICBiY2Z0b29scyBxdWVyeSBcCiAgICAtLWluY2x1ZGUgJ0ZJTFRFUj0iUEFTUyInIFwKICAgIC0tZXhjbHVkZSAnR1R+IlwuIicgXAogICAgLS1mb3JtYXQgJyVDSFJPTSwlUE9TLCVGSUxURVIsJUlORk8vU1ZUWVBFLFslTE5dXG4nIFwKICAtLW91dHB1dCAkb3V0X2Rpci8kc2FtcGxlLmNzdiBcCiAgJGluX3ZjZiA7CmRvbmUKYGBgCgojIEFuYWx5c2lzCgojIyBSZWFkIGluIFNWIGRhdGEKCiMjIyBTVmlwZXIgcG9saXNoZWQKCmBgYHtyfQppbl9kaXIgPSBoZXJlOjpoZXJlKCJkYXRhIiwgInN2X2FuYWx5c2lzLzIwMjEwMjE3X3N2aXBlcl9maWx0ZXJfcGFzcyIpCgppbl9maWxlcyA9IGxpc3QuZmlsZXMoaW5fZGlyLCBmdWxsLm5hbWVzID0gVCkKbmFtZXMoaW5fZmlsZXMpID0gYmFzZW5hbWUoaW5fZmlsZXMpICU+JSAKICBzdHJfcmVtb3ZlKCIuY3N2IikKCnN2X2RmX3BvbCA9IGxhcHBseShpbl9maWxlcywgZnVuY3Rpb24oaW5fZmlsZSl7CiAgZGYgPSByZWFkcjo6cmVhZF9jc3YoaW5fZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCJDSFJPTSIsICJQT1MiLCAiQUxUIiwgIlNWTEVOIiwgIlNWVFlQRSIsICJDSFIyIiwgIkVORCIsICJHVCIsICJMTiIsICJTVCIpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGMoImNpY2ljY2ljaWMiKSkKICAKICByZXR1cm4oZGYpCn0pICU+JSAKICBkcGx5cjo6YmluZF9yb3dzKC5pZCA9ICJTQU1QTEUiKSAlPiUgCiAgIyBhZGQgImNociIgdG8gYmVnaW5uaW5nIG9mIENIUk9NIGNvbHVtbgogIGRwbHlyOjptdXRhdGUoQ0hST00gPSBwYXN0ZSgiY2hyIiwgQ0hST00sIHNlcCA9ICIiKSkKYGBgCgojIyMgT05UIHJhdwoKYGBge3J9CmluX2RpciA9IGhlcmU6OmhlcmUoImRhdGEiLCAic3ZfYW5hbHlzaXMvMjAyMTAyMTdfcmF3X29udF9maWx0ZXJfcGFzcyIpCgppbl9maWxlcyA9IGxpc3QuZmlsZXMoaW5fZGlyLCBmdWxsLm5hbWVzID0gVCkKbmFtZXMoaW5fZmlsZXMpID0gYmFzZW5hbWUoaW5fZmlsZXMpICU+JSAKICBzdHJfcmVtb3ZlKCIuY3N2IikKCnN2X2RmX3JhdyA9IGxhcHBseShpbl9maWxlcywgZnVuY3Rpb24oaW5fZmlsZSl7CiAgZGYgPSByZWFkcjo6cmVhZF9jc3YoaW5fZmlsZSwKICAgICAgICAgICAgICAgICAgICAgICBjb2xfbmFtZXMgPSBjKCJDSFJPTSIsICJQT1MiLCAiQUxUIiwgIlNWTEVOIiwgIlNWVFlQRSIsICJDSFIyIiwgIkVORCIsICJHVCIsICJMTiIsICJTVCIpLAogICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGMoImNpY2ljY2ljaWMiKSkKICAKICByZXR1cm4oZGYpCn0pICU+JSAKICBkcGx5cjo6YmluZF9yb3dzKC5pZCA9ICJTQU1QTEUiKSAlPiUgCiAgIyBhZGQgImNociIgdG8gYmVnaW5uaW5nIG9mIENIUk9NIGNvbHVtbgogIGRwbHlyOjptdXRhdGUoQ0hST00gPSBwYXN0ZSgiY2hyIiwgQ0hST00sIHNlcCA9ICIiKSkKYGBgCgojIyMgQ29tYmluZSBpbnRvIHNpbmdsZSBkZgoKYGBge3J9CnN2X2RmID0gbGlzdCgicG9saXNoZWQiID0gc3ZfZGZfcG9sLAogICAgICAgICAgICAgInJhdyIgPSBzdl9kZl9yYXcpICU+JSAKICBkcGx5cjo6YmluZF9yb3dzKC5pZCA9ICJEQVRBU0VUIikgJT4lIAogICMgZmFjdG9yIHNhbXBsZXMgYW5kIGRhdGFzZXQKICBkcGx5cjo6bXV0YXRlKFNBTVBMRSA9IGZhY3RvcihTQU1QTEUsIGxldmVscyA9IG9udF9zYW1wbGVzKSwKICAgICAgICAgICAgICAgIERBVEFTRVQgPSBmYWN0b3IoREFUQVNFVCwgbGV2ZWxzID0gYygicmF3IiwgInBvbGlzaGVkIikpKQpgYGAKCiMjIFBsb3QgY291bnRzIG9mIFNWIHR5cGVzICh0b3RhbCkKCmBgYHtyfQpzdnR5cGVfaGlzdF9wYWwgPSBjb2xvclJhbXBQYWxldHRlKHBhbF9wYWRkbGUpKDUpW2MoMToyLCA0OjUpXQoKIyBIaXN0b2dyYW0gb2YgTE4Kc3Z0eXBlX2Rpc3RpbmN0X2RmID0gc3ZfZGYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoREFUQVNFVCA9PSAicG9saXNoZWQiLAogICAgICAgICAgICAgICAgU1ZUWVBFICE9ICJUUkEiKSAlPiUgCiAgZHBseXI6Om11dGF0ZShTVlRZUEUgPSBmYWN0b3IoU1ZUWVBFLCBsZXZlbHMgPSBjKCJERUwiLCAiSU5TIiwgIkRVUCIsICJJTlYiKSkpICU+JSAKICBkcGx5cjo6c2VsZWN0KFNWVFlQRSwgQ0hST00sIFBPUywgRU5ELCBMTikgJT4lIAogIGRwbHlyOjpkaXN0aW5jdCgpCiAgCnN2bGVuX2NvdW50c19wbG90ID0gc3Z0eXBlX2Rpc3RpbmN0X2RmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBsb2cxMChMTiksCiAgICAgICAgICAgICB5ID0gaWZlbHNlKGxvZzEwKC4uY291bnQuLikgPCAwLAogICAgICAgICAgICAgICAgICAgICAgICAwLAogICAgICAgICAgICAgICAgICAgICAgICBsb2cxMCguLmNvdW50Li4pKSwKICAgICAgICAgICAgIGZpbGwgPSBTVlRZUEUsCiAgICAgICAgICAgICBjb2xvdXIgPSBTVlRZUEUpKSArCiAgICBnZW9tX2FyZWEoc3RhdCA9ICJiaW4iLAogICAgICAgICAgICAgIGJpbnMgPSAxMDApICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHN2dHlwZV9oaXN0X3BhbCkgKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBrYXJ5b3Bsb3RlUjo6ZGFya2VyKHN2dHlwZV9oaXN0X3BhbCkpICsKICAgIGd1aWRlcyhmaWxsID0gRikgKwogICAgZ3VpZGVzKGNvbG91ciA9IEYpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgNiwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygxLCA2KSkgKwogICAgZmFjZXRfd3JhcCh+U1ZUWVBFLCBucm93ID0gMiwgbmNvbCA9IDIpICsKICAgIHhsYWIoZXhwcmVzc2lvbihsb2dbMTBdKGxlbmd0aCkpKSArCiAgICB5bGFiKGV4cHJlc3Npb24obG9nWzEwXShjb3VudCkpKSArCiAgICB0aGVtZV9jb3dwbG90KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkKICAgICAgICAgICkgIAoKc3ZsZW5fY291bnRzX3Bsb3QKYGBgCgojIyBQbG90IGNvdW50cyBvZiBTViB0eXBlcyAocGVyIHNhbXBsZSkKCkdldCBvcmRlciBvZiBTViB0eXBlIGJ5IGZyZXF1ZW5jeQoKYGBge3J9CiMgR2V0IG9yZGVyCnR5cGVfb3JkZXIgPSBkcGx5cjo6Y291bnQoc3ZfZGYsIFNWVFlQRSkgJT4lIAogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSAKICBkcGx5cjo6cHVsbChTVlRZUEUpCgojIFNldCBwYWxldHRlCnBhbF9zdnR5cGUgPSBnckRldmljZXM6OmNvbG9yUmFtcFBhbGV0dGUocGFsX2JyYWluYm93KShsZW5ndGgob250X3NhbXBsZXNfcG9sKSkKbmFtZXMocGFsX3N2dHlwZSkgPSBvbnRfc2FtcGxlc19wb2wKYGBgCgojIyMgQWxsCgpgYGB7cn0Kc3ZfY291bnRzX2FsbCA9IHN2X2RmICU+JSAKICBkcGx5cjo6ZmlsdGVyKERBVEFTRVQgPT0gInBvbGlzaGVkIikgJT4lCiAgZ3JvdXBfYnkoU0FNUExFLCBTVlRZUEUpICU+JSAKICBzdW1tYXJpc2UoTiA9IG4oKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoRkFDRVQgPSAiVE9UQUwiKSAlPiUgCiAgZHBseXI6OnVuZ3JvdXAoKQpgYGAKCiMjIyBTaW5nbGV0b25zCgpgYGB7ciwgcmVzdWx0cyA9ICdhc2lzJ30KIyBDcmVhdGUgREYgd2l0aCBTQU1QTEUgZm9yIGJpbmRpbmcgbGF0ZXIKc3ZfZGZfcG9sX3NhbXBzID0gc3ZfZGYgJT4lIAogICMgZXhjbHVkZSByYXcgZGF0YSwgdGFrZSBvbmx5IHBvbGlzaGVkCiAgZHBseXI6OmZpbHRlcihEQVRBU0VUID09ICJwb2xpc2hlZCIpICU+JSAKICAjIHNlbGVjdCBvbmx5IHRhcmdldCBjb2xzCiAgZHBseXI6OnNlbGVjdChDSFJPTSwgUE9TLCBTVlRZUEUsIExOLCBTQU1QTEUpCgojIENyZWF0ZSBERiB3aXRob3V0IFNBTVBMRSBmb3IgZGV0ZWN0aW5nIGR1cGxpY2F0ZXMKc3ZfZGZfcG9sX2R1cGVzID0gc3ZfZGYgJT4lIAogICMgZXhjbHVkZSByYXcgZGF0YSwgdGFrZSBvbmx5IHBvbGlzaGVkCiAgZHBseXI6OmZpbHRlcihEQVRBU0VUID09ICJwb2xpc2hlZCIpICU+JSAKICAjIHNlbGVjdCBvbmx5IHRhcmdldCBjb2xzCiAgZHBseXI6OnNlbGVjdChDSFJPTSwgUE9TLCBTVlRZUEUsIExOKQoKIyMgR2V0IHVuaXF1ZSByb3dzCnVxX3N2cyA9IHN2X2RmX3BvbF9kdXBlc1shKGR1cGxpY2F0ZWQoc3ZfZGZfcG9sX2R1cGVzKSB8IGR1cGxpY2F0ZWQoc3ZfZGZfcG9sX2R1cGVzLCBmcm9tTGFzdCA9IFQpKSwgXQoKIyBKb2luIGJhY2sgd2l0aCBvdGhlciB2YXJpYWJsZXMKc3Zfc2luZ3MgPSBkcGx5cjo6cmlnaHRfam9pbihzdl9kZl9wb2xfc2FtcHMsIHVxX3N2cykKCmtuaXRyOjprYWJsZShoZWFkKHN2X3NpbmdzKSkKYGBgCgpgYGB7cn0KIyBHZXQgc2luZ2xldG9uIGNvdW50cwpzdl9jb3VudHNfc2luZ3MgPSBzdl9zaW5ncyAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoU0FNUExFLCBTVlRZUEUpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKE4gPSBuKCkpICU+JSAKICBkcGx5cjo6bXV0YXRlKEZBQ0VUID0gIlNJTkdMRVRPTlMiKSAlPiUgCiAgZHBseXI6OnVuZ3JvdXAoKQpgYGAKCiMjIyBCaW5kIHRvZ2V0aGVyIGFuZCBwbG90CgpgYGB7cn0KIyBCaW5kIERGcwpzdl9jb3VudHMgPSBkcGx5cjo6YmluZF9yb3dzKHN2X2NvdW50c19hbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ZfY291bnRzX3NpbmdzKSAlPiUgCiAgZHBseXI6Om11dGF0ZShGQUNFVCA9IGZhY3RvcihGQUNFVCwgbGV2ZWxzID0gYygiVE9UQUwiLCAiU0lOR0xFVE9OUyIpKSwKICAgICAgICAgICAgICAgIFNWVFlQRSA9IGZhY3RvcihTVlRZUEUsIGxldmVscyA9IHR5cGVfb3JkZXIpKQoKIyBTZXQgcGFsZXR0ZQpwYWxfc3Zjb3VudHMgPSBnckRldmljZXM6OmNvbG9yUmFtcFBhbGV0dGUocGFsX3NtcmFydm8pKGxlbmd0aChvbnRfc2FtcGxlcykpCm5hbWVzKHBhbF9zdmNvdW50cykgPSBvbnRfc2FtcGxlcwoKIyBQbG90CnN2dHlwZV9jb3VudHNfcGxvdCA9IHN2X2NvdW50cyAlPiUgCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9jb2woYWVzKFNBTVBMRSwgTiwgZmlsbCA9IFNBTVBMRSkpICsKICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoRkFDRVQpLAogICAgICAgICAgICAgICBjb2xzID0gdmFycyhTVlRZUEUpLHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxfc3Zjb3VudHMpICsKICAgIHRoZW1lX2Nvd3Bsb3QoKSArCiAgICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUsYW5nbGUgPSA0NSxoanVzdCA9IDEpLAogICAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSArCiAgICBndWlkZXMoZmlsbCA9IEYpICsKICAgIHhsYWIoIlNhbXBsZSIpICsKICAgIHlsYWIoIkNvdW50IikKCnN2dHlwZV9jb3VudHNfcGxvdCAKYGBgCgpgYGB7cn0KZ2dwbG90bHkoc3Z0eXBlX2NvdW50c19wbG90KQpgYGAKCjwhLS0KYGBge3J9CmZpbmFsX3N2dHlwZSA9IGdnZHJhdygpICsKICBkcmF3X3Bsb3Qoc3Z0eXBlX3BsdCwgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IC42LCBoZWlnaHQgPSAxKSArCiAgZHJhd19wbG90KHN2dHlwZV9oaXN0c1tbMV1dLCB4ID0gLjYsIHkgPSAuNSwgd2lkdGggPTAuMiwgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHN2dHlwZV9oaXN0c1tbMl1dLCB4ID0gLjgsIHkgPSAuNSwgd2lkdGggPTAuMiwgaGVpZ2h0ID0gMC41KSArCiAgZHJhd19wbG90KHN2dHlwZV9oaXN0c1tbM11dLCB4ID0gLjYsIHkgPSAwLCB3aWR0aCA9MC4yLCBoZWlnaHQgPSAwLjUpICsKICBkcmF3X3Bsb3Qoc3Z0eXBlX2hpc3RzW1s0XV0sIHggPSAuOCwgeSA9IDAsIHdpZHRoID0wLjIsIGhlaWdodCA9IDAuNSkgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoIkEiLCAiQiIpLCBzaXplID0gMTUsCiAgICAgICAgICAgICAgICAgIHggPSBjKDAsIC42KSwgeSA9IGMoMSwgMSkpCgpmaW5hbF9zdnR5cGUKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQpnZ3NhdmUoaGVyZTo6aGVyZSgicGxvdHMiLCAic3ZfYW5hbHlzaXMiLCAiMjAyMTAyMjVfc3ZfdHlwZV9jb3VudHMuc3ZnIiksCiAgICAgICBkZXZpY2UgPSAic3ZnIiwKICAgICAgIHVuaXRzID0gImNtIiwKICAgICAgIHdpZHRoID0gMzAsCiAgICAgICBoZWlnaHQgPSAxMCkKCmdnc2F2ZShoZXJlOjpoZXJlKCJwbG90cyIsICJzdl9hbmFseXNpcyIsICIyMDIxMDIyNV9zdl90eXBlX2NvdW50cy5wbmciKSwKICAgICAgIGRldmljZSA9ICJwbmciLAogICAgICAgZHBpID0gNDAwLAogICAgICAgdW5pdHMgPSAiY20iLAogICAgICAgd2lkdGggPSAzMCwKICAgICAgIGhlaWdodCA9IDEwKQpgYGAKCi0tPgoKIyMgQ2lyY29zIHBsb3RzCgpTVkdzIGJlY29tZSB2ZXJ5IGxhcmdlICh+ODAgTUIpLiBIZW5jZSBQTkcuCgpDcmVhdGUgc2NhZmZvbGQKCmBgYHtyfQojIFJlYWQgaW4gY2hyb21vc29tZSBkYXRhCmNocm9tcyA9IHJlYWQudGFibGUoaGVyZTo6aGVyZSgiZGF0YS9Pcnl6aWFzX2xhdGlwZXMuQVNNMjIzNDY3djEuZG5hLnRvcGxldmVsLmZhX2Nocl9jb3VudHMudHh0IikpICU+JSAKICBkcGx5cjo6c2VsZWN0KGNociA9IFYxLCBlbmQgPSBWMikgJT4lIAogIGRwbHlyOjptdXRhdGUoY2hyID0gcGFzdGUoImNociIsIGNociwgc2VwID0gIiIpLAogICAgICAgICAgICAgICAgc3RhcnQgPSAwLAogICAgICAgICAgICAgICAgZW5kID0gYXMubnVtZXJpYyhlbmQpKSAlPiUgCiAgZHBseXI6OnNlbGVjdChjaHIsIHN0YXJ0LCBlbmQpCmBgYAoKIyMjIERFTAoKYGBge3J9CnN2X2RlbHMgPSBzdl9kZiAlPiUgCiAgZHBseXI6OmZpbHRlcihEQVRBU0VUID09ICJwb2xpc2hlZCIsCiAgICAgICAgICAgICAgICBTVlRZUEUgPT0gIkRFTCIpICU+JSAKICBkcGx5cjo6c2VsZWN0KENIUk9NLCBQT1MsIEVORCwgU0FNUExFLCBMTikgJT4lCiAgZHBseXI6Om11dGF0ZShTQU1QTEUgPSBmYWN0b3IoU0FNUExFLCBsZXZlbHMgPSBvbnRfc2FtcGxlc19wb2wpKSAlPiUgCiAgc3BsaXQoLiwgZiA9IC4kU0FNUExFKQoKYGBgCgpgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJzdl9hbmFseXNpcyIsICIyMDIxMDIyNF9zdl9kZWxzX2xpbmVzLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpwbmcob3V0X3Bsb3QsCiAgICB3aWR0aCA9IDIwLAogICAgaGVpZ2h0ID0gMjAsCiAgICB1bml0cyA9ICJjbSIsCiAgICByZXMgPSA0MDApCgojIEdldCBtYXggdmFsdWUgZm9yIGB5bGltYAptYXhfbGVuID0gbWF4KHNhcHBseShzdl9kZWxzLCBmdW5jdGlvbihzYW1wbGUpIG1heChzYW1wbGUkTE4pKSkKbWF4X2xlbiA9IHJvdW5kLmNob29zZShtYXhfbGVuLCAxZTUsIGRpciA9IDEpCgojIENob29zZSBwYWxldHRlCnBhbCA9IGdyRGV2aWNlczo6Y29sb3JSYW1wUGFsZXR0ZShwYWxfc21yYXJ2bykobGVuZ3RoKHN2X2RlbHMpKQoKIyBTZXQgcGFyYW1ldGVycwojIyBEZWNyZWFzZSBjZWxsIHBhZGRpbmcgZnJvbSBkZWZhdWx0IGMoMC4wMiwgMS4wMCwgMC4wMiwgMS4wMCkKY2lyY29zLnBhcihjZWxsLnBhZGRpbmcgPSBjKDAsIDAsIDAsIDApLAogICAgICAgICAgIHRyYWNrLm1hcmdpbiA9IGMoMCwgMCksCiAgICAgICAgICAgZ2FwLmRlZ3JlZSA9IGMocmVwKDEsIG5yb3coY2hyb21zKSAtIDEpLCAxNCkpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKY291bnRlciA9IDAKbGFwcGx5KHN2X2RlbHMsIGZ1bmN0aW9uKHNhbXBsZSkgewogICMgU2V0IGNvdW50ZXIKICBjb3VudGVyIDw8LSBjb3VudGVyICsgMQogICMgQ3JlYXRlIHRyYWNrCiAgY2lyY29zLmdlbm9taWNUcmFjayhzYW1wbGUsCiAgICBwYW5lbC5mdW4gPSBmdW5jdGlvbihyZWdpb24sIHZhbHVlLCAuLi4pIHsKICAgICAgY2lyY29zLmdlbm9taWNMaW5lcyhyZWdpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBwYWxbY291bnRlcl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2V4ID0gMC4wNSkKICB9LAogIHRyYWNrLmhlaWdodCA9IDAuMDcsCiAgYmcuYm9yZGVyID0gTkEsCiAgeWxpbSA9IGMoMCwgbWF4X2xlbikpCiAgCiAgIyBBZGQgU1YgbGVuZ3RoIHktYXhpcyBsYWJlbAogIGNpcmNvcy55YXhpcyhzaWRlID0gInJpZ2h0IiwKICAgICAgICAgICAgIGF0ID0gYygyLjVlNSwgbWF4X2xlbiksCiAgICAgICAgICAgICBsYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpLAogICAgICAgICAgICAgdGljay5sZW5ndGggPSAyCiAgICAgICAgICAgICApCiAgCgogICMgQWRkIFNBTVBMRSB5LWF4aXMgbGFiZWwKICBjaXJjb3MudGV4dCgyZTYsIDIuNWU1LAogICAgICAgICAgICAgIGxhYmVscyA9IG5hbWVzKHN2X2RlbHMpW2NvdW50ZXJdLAogICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9ICJjaHIxIiwKICAgICAgICAgICAgICBjZXggPSAwLjQqcGFyKCJjZXgiKSkKfSkKCgpjaXJjb3MuY2xlYXIoKQoKZGV2Lm9mZigpCmBgYAoKYGBge3IsIGluY2x1ZGUgPSBGfQojIGNvcHkgdG8gc2FtZSBkaXJlY3RvcnkgYXMgY3VycmVudCBub3RlYm9vawpjdXJyZW50X2RpciA9IGRpcm5hbWUocnN0dWRpb2FwaTo6Z2V0U291cmNlRWRpdG9yQ29udGV4dCgpJHBhdGgpCgpuZXdfcGF0aCA9IGZpbGUucGF0aChjdXJyZW50X2RpciwgYmFzZW5hbWUob3V0X3Bsb3QpKQoKaWYgKGZpbGUuZXhpc3RzKG5ld19wYXRoKSAhPSBUKXsKICBmaWxlLmNvcHkob3V0X2ZpbGUsIG5ld19wYXRoKQp9CmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGJhc2VuYW1lKG91dF9wbG90KSkKYGBgCgojIyMgSU5TCgpbTk9URV17Y29sb3I9InJlZCJ9OiAyNTk4Mi8zNTE5OTYgaW5zZXJ0aW9ucyBoYXZlIGFuIEVORCB0aGF0IGlzIGxlc3MgdGhhbiBQT1MuIE1ha2UgdGhlIEVORCB0aGUgc2FtZSBhcyBQT1MgZm9yIHRoZSBwdXJwb3NlcyBvZiBwbG90dGluZyB0aGVpciBsb2NhdGlvbi4KCmBgYHtyfQpzdl9pbnMgPSBzdl9kZiAlPiUgCiAgZHBseXI6OmZpbHRlcihEQVRBU0VUID09ICJwb2xpc2hlZCIsCiAgICAgICAgICAgICAgICBTVlRZUEUgPT0gIklOUyIpICU+JSAKICBkcGx5cjo6c2VsZWN0KENIUk9NLCBQT1MsIEVORCwgU0FNUExFLCBMTikgJT4lCiAgIyBGYWN0b3Jpc2UgU0FNUExFIHRvIG9yZGVyCiAgZHBseXI6Om11dGF0ZShTQU1QTEUgPSBmYWN0b3IoU0FNUExFLCBsZXZlbHMgPSBvbnRfc2FtcGxlc19wb2wpKSAlPiUgCiAgIyBpZiBFTkQgaXMgbGVzcyB0aGFuIFBPUywgbWFrZSBpdCB0aGUgc2FtZSBhcyBQT1MKICBkcGx5cjo6bXV0YXRlKEVORCA9IGRwbHlyOjppZl9lbHNlKEVORCA8IFBPUywgUE9TLCBFTkQpKSAlPiUgCiMgIGRwbHlyOjpzbGljZV9zYW1wbGUobiA9IDEwMDAwKSAlPiUgCiAgc3BsaXQoLiwgZiA9IC4kU0FNUExFKQpgYGAKCmBgYHtyfQpvdXRfcGxvdCA9IGhlcmU6OmhlcmUoInBsb3RzIiwgInN2X2FuYWx5c2lzIiwgIjIwMjEwMjI0X3N2X2luc19saW5lcy5wbmciKQpgYGAKCmBgYHtyLCBldmFsID0gRn0KcG5nKG91dF9wbG90LAogICAgd2lkdGggPSAyMCwKICAgIGhlaWdodCA9IDIwLAogICAgdW5pdHMgPSAiY20iLAogICAgcmVzID0gNDAwKQoKIyBHZXQgbWF4IHZhbHVlIGZvciBgeWxpbWAKbWF4X2xlbiA9IG1heChzYXBwbHkoc3ZfaW5zLCBmdW5jdGlvbihzYW1wbGUpIG1heChzYW1wbGUkTE4pKSkKbWF4X2xlbiA9IHJvdW5kLmNob29zZShtYXhfbGVuLCAxZTUsIGRpciA9IDEpCgojIENob29zZSBwYWxldHRlCnBhbCA9IGZpc2h1YWxpemU6OmZpc2gobiA9IGxlbmd0aChzdl9pbnMpLCBvcHRpb24gPSAiQ2lycmhpbGFicnVzX3NvbG9yZW5zaXMiKQoKIyBTZXQgcGFyYW1ldGVycwojIyBEZWNyZWFzZSBjZWxsIHBhZGRpbmcgZnJvbSBkZWZhdWx0IGMoMC4wMiwgMS4wMCwgMC4wMiwgMS4wMCkKY2lyY29zLnBhcihjZWxsLnBhZGRpbmcgPSBjKDAsIDAsIDAsIDApLAogICAgICAgICAgIHRyYWNrLm1hcmdpbiA9IGMoMCwgMCksCiAgICAgICAgICAgZ2FwLmRlZ3JlZSA9IGMocmVwKDEsIG5yb3coY2hyb21zKSAtIDEpLCAxNCkpCiMgSW5pdGlhbGl6ZSBwbG90CmNpcmNvcy5pbml0aWFsaXplV2l0aElkZW9ncmFtKGNocm9tcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdFR5cGUgPSBjKCJheGlzIiwgImxhYmVscyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWpvci5ieSA9IDFlNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy5sYWJlbHMuY2V4ID0gMC4yNSpwYXIoImNleCIpKQoKY291bnRlciA9IDAKbGFwcGx5KHN2X2lucywgZnVuY3Rpb24oc2FtcGxlKSB7CiAgIyBTZXQgY291bnRlcgogIGNvdW50ZXIgPDwtIGNvdW50ZXIgKyAxCiAgIyBDcmVhdGUgdHJhY2sKICBjaXJjb3MuZ2Vub21pY1RyYWNrKHNhbXBsZSwKICAgIHBhbmVsLmZ1biA9IGZ1bmN0aW9uKHJlZ2lvbiwgdmFsdWUsIC4uLikgewogICAgICBjaXJjb3MuZ2Vub21pY0xpbmVzKHJlZ2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImgiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHBhbFtjb3VudGVyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjZXggPSAwLjA1KQogIH0sCiAgdHJhY2suaGVpZ2h0ID0gMC4wNywKICBiZy5ib3JkZXIgPSBOQSwKICB5bGltID0gYygwLCBtYXhfbGVuKSkKICAKICAjIEFkZCBTViBsZW5ndGggeS1heGlzIGxhYmVsCiAgY2lyY29zLnlheGlzKHNpZGUgPSAicmlnaHQiLAogICAgICAgICAgICAgYXQgPSBjKDIuNWU1LCBtYXhfbGVuKSwKICAgICAgICAgICAgIGxhYmVscy5jZXggPSAwLjI1KnBhcigiY2V4IiksCiAgICAgICAgICAgICB0aWNrLmxlbmd0aCA9IDIKICAgICAgICAgICAgICkKICAKCiAgIyBBZGQgU0FNUExFIHktYXhpcyBsYWJlbAogIGNpcmNvcy50ZXh0KDJlNiwgMi41ZTUsCiAgICAgICAgICAgICAgbGFiZWxzID0gbmFtZXMoc3ZfaW5zKVtjb3VudGVyXSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiAgICAgICAgICAgICAgY2V4ID0gMC40KnBhcigiY2V4IikpCn0pCgoKY2lyY29zLmNsZWFyKCkKCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKG91dF9wbG90KSkKCmlmIChmaWxlLmV4aXN0cyhuZXdfcGF0aCkgIT0gVCl7CiAgZmlsZS5jb3B5KG91dF9wbG90LCBuZXdfcGF0aCkKfQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfcGxvdCkpCmBgYAoKIyMjIERVUAoKW05PVEVde2NvbG9yPSJyZWQifTogMzA3LzI2ODIzIGR1cGxpY2F0aW9ucyBoYXZlIGFuIEVORCB0aGF0IGlzIGxlc3MgdGhhbiBQT1MuIE1ha2UgdGhlIEVORCB0aGUgc2FtZSBhcyBQT1MuCgpgYGB7cn0Kc3ZfZHVwcyA9IHN2X2RmICU+JSAKICBkcGx5cjo6ZmlsdGVyKERBVEFTRVQgPT0gInBvbGlzaGVkIiwKICAgICAgICAgICAgICAgIFNWVFlQRSA9PSAiRFVQIikgJT4lIAogIGRwbHlyOjpzZWxlY3QoQ0hST00sIFBPUywgRU5ELCBTQU1QTEUsIExOKSAlPiUKICBkcGx5cjo6bXV0YXRlKFNBTVBMRSA9IGZhY3RvcihTQU1QTEUsIGxldmVscyA9IG9udF9zYW1wbGVzX3BvbCkpICU+JSAKICAjIGlmIEVORCBpcyBsZXNzIHRoYW4gUE9TLCBtYWtlIGl0IHRoZSBzYW1lIGFzIFBPUwogIGRwbHlyOjptdXRhdGUoRU5EID0gZHBseXI6OmlmX2Vsc2UoRU5EIDwgUE9TLCBQT1MsIEVORCkpICU+JSAKIyAgZHBseXI6OnNsaWNlX3NhbXBsZShuID0gMTAwMDApICU+JSAKICBzcGxpdCguLCBmID0gLiRTQU1QTEUpCmBgYAoKYGBge3J9Cm91dF9wbG90ID0gaGVyZTo6aGVyZSgicGxvdHMiLCAic3ZfYW5hbHlzaXMiLCAiMjAyMTAyMjRfc3ZfZHVwc19saW5lcy5wbmciKQpgYGAKCmBgYHtyLCBldmFsID0gRn0KcG5nKG91dF9wbG90LAogICAgd2lkdGggPSAyMCwKICAgIGhlaWdodCA9IDIwLAogICAgdW5pdHMgPSAiY20iLAogICAgcmVzID0gNDAwKQoKIyBHZXQgbWF4IHZhbHVlIGZvciBgeWxpbWAKbWF4X2xlbiA9IG1heChzYXBwbHkoc3ZfZHVwcywgZnVuY3Rpb24oc2FtcGxlKSBtYXgoc2FtcGxlJExOKSkpCm1heF9sZW4gPSByb3VuZC5jaG9vc2UobWF4X2xlbiwgMWU1LCBkaXIgPSAxKQoKIyBDaG9vc2UgcGFsZXR0ZQpwYWwgPSBmaXNodWFsaXplOjpmaXNoKG4gPSBsZW5ndGgoc3ZfZHVwcyksIG9wdGlvbiA9ICJHcmFtbWFfbG9yZXRvIikKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgMTQpKQojIEluaXRpYWxpemUgcGxvdApjaXJjb3MuaW5pdGlhbGl6ZVdpdGhJZGVvZ3JhbShjaHJvbXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RUeXBlID0gYygiYXhpcyIsICJsYWJlbHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFqb3IuYnkgPSAxZTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMubGFiZWxzLmNleCA9IDAuMjUqcGFyKCJjZXgiKSkKCmNvdW50ZXIgPSAwCmxhcHBseShzdl9kdXBzLCBmdW5jdGlvbihzYW1wbGUpIHsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAjIENyZWF0ZSB0cmFjawogIGNpcmNvcy5nZW5vbWljVHJhY2soc2FtcGxlLAogICAgcGFuZWwuZnVuID0gZnVuY3Rpb24ocmVnaW9uLCB2YWx1ZSwgLi4uKSB7CiAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gcGFsW2NvdW50ZXJdLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNleCA9IDAuMDUpCiAgfSwKICB0cmFjay5oZWlnaHQgPSAwLjA3LAogIGJnLmJvcmRlciA9IE5BLAogIHlsaW0gPSBjKDAsIG1heF9sZW4pKQogIAogICMgQWRkIFNWIGxlbmd0aCB5LWF4aXMgbGFiZWwKICBjaXJjb3MueWF4aXMoc2lkZSA9ICJyaWdodCIsCiAgICAgICAgICAgICBhdCA9IGMoMi41ZTUsIG1heF9sZW4pLAogICAgICAgICAgICAgbGFiZWxzLmNleCA9IDAuMjUqcGFyKCJjZXgiKSwKICAgICAgICAgICAgIHRpY2subGVuZ3RoID0gMgogICAgICAgICAgICAgKQogIAoKICAjIEFkZCBTQU1QTEUgeS1heGlzIGxhYmVsCiAgY2lyY29zLnRleHQoMmU2LCAyLjVlNSwKICAgICAgICAgICAgICBsYWJlbHMgPSBuYW1lcyhzdl9kdXBzKVtjb3VudGVyXSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiAgICAgICAgICAgICAgY2V4ID0gMC40KnBhcigiY2V4IikpCn0pCgoKY2lyY29zLmNsZWFyKCkKCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKG91dF9wbG90KSkKCmlmIChmaWxlLmV4aXN0cyhuZXdfcGF0aCkgIT0gVCl7CiAgZmlsZS5jb3B5KG91dF9wbG90LCBuZXdfcGF0aCkKfQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfcGxvdCkpCmBgYAoKIyMjIElOVgoKYGBge3J9CnN2X2ludnMgPSBzdl9kZiAlPiUgCiAgZHBseXI6OmZpbHRlcihEQVRBU0VUID09ICJwb2xpc2hlZCIsCiAgICAgICAgICAgICAgICBTVlRZUEUgPT0gIklOViIpICU+JSAKICBkcGx5cjo6c2VsZWN0KENIUk9NLCBQT1MsIEVORCwgU0FNUExFLCBMTikgJT4lCiAgZHBseXI6Om11dGF0ZShTQU1QTEUgPSBmYWN0b3IoU0FNUExFLCBsZXZlbHMgPSBvbnRfc2FtcGxlc19wb2wpKSAlPiUgCiAgIyBpZiBFTkQgaXMgbGVzcyB0aGFuIFBPUywgbWFrZSBpdCB0aGUgc2FtZSBhcyBQT1MKIyAgZHBseXI6Om11dGF0ZShFTkQgPSBkcGx5cjo6aWZfZWxzZShFTkQgPCBQT1MsIFBPUywgRU5EKSkgJT4lIAojICBkcGx5cjo6c2xpY2Vfc2FtcGxlKG4gPSAxMDAwMCkgJT4lIAogIHNwbGl0KC4sIGYgPSAuJFNBTVBMRSkKYGBgCgpgYGB7cn0Kb3V0X3Bsb3QgPSBoZXJlOjpoZXJlKCJwbG90cyIsICJzdl9hbmFseXNpcyIsICIyMDIxMDIyNF9zdl9pbnZzX2xpbmVzLnBuZyIpCmBgYAoKYGBge3IsIGV2YWwgPSBGfQpwbmcob3V0X3Bsb3QsCiAgICB3aWR0aCA9IDIwLAogICAgaGVpZ2h0ID0gMjAsCiAgICB1bml0cyA9ICJjbSIsCiAgICByZXMgPSA0MDApCgojIEdldCBtYXggdmFsdWUgZm9yIGB5bGltYAptYXhfbGVuID0gbWF4KHNhcHBseShzdl9pbnZzLCBmdW5jdGlvbihzYW1wbGUpIG1heChzYW1wbGUkTE4pKSkKbWF4X2xlbiA9IHJvdW5kLmNob29zZShtYXhfbGVuLCAxZTUsIGRpciA9IDEpCgojIENob29zZSBwYWxldHRlCnBhbCA9IGZpc2h1YWxpemU6OmZpc2gobiA9IGxlbmd0aChzdl9pbnZzKSwgb3B0aW9uID0gIkxlcG9taXNfbWVnYWxvdGlzIikKCiMgU2V0IHBhcmFtZXRlcnMKIyMgRGVjcmVhc2UgY2VsbCBwYWRkaW5nIGZyb20gZGVmYXVsdCBjKDAuMDIsIDEuMDAsIDAuMDIsIDEuMDApCmNpcmNvcy5wYXIoY2VsbC5wYWRkaW5nID0gYygwLCAwLCAwLCAwKSwKICAgICAgICAgICB0cmFjay5tYXJnaW4gPSBjKDAsIDApLAogICAgICAgICAgIGdhcC5kZWdyZWUgPSBjKHJlcCgxLCBucm93KGNocm9tcykgLSAxKSwgMTQpKQojIEluaXRpYWxpemUgcGxvdApjaXJjb3MuaW5pdGlhbGl6ZVdpdGhJZGVvZ3JhbShjaHJvbXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RUeXBlID0gYygiYXhpcyIsICJsYWJlbHMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFqb3IuYnkgPSAxZTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMubGFiZWxzLmNleCA9IDAuMjUqcGFyKCJjZXgiKSkKCmNvdW50ZXIgPSAwCmxhcHBseShzdl9pbnZzLCBmdW5jdGlvbihzYW1wbGUpIHsKICAjIFNldCBjb3VudGVyCiAgY291bnRlciA8PC0gY291bnRlciArIDEKICAjIENyZWF0ZSB0cmFjawogIGNpcmNvcy5nZW5vbWljVHJhY2soc2FtcGxlLAogICAgcGFuZWwuZnVuID0gZnVuY3Rpb24ocmVnaW9uLCB2YWx1ZSwgLi4uKSB7CiAgICAgIGNpcmNvcy5nZW5vbWljTGluZXMocmVnaW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gcGFsW2NvdW50ZXJdLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNleCA9IDAuMDUpCiAgfSwKICB0cmFjay5oZWlnaHQgPSAwLjA3LAogIGJnLmJvcmRlciA9IE5BLAogIHlsaW0gPSBjKDAsIG1heF9sZW4pKQogIAogICMgQWRkIFNWIGxlbmd0aCB5LWF4aXMgbGFiZWwKICBjaXJjb3MueWF4aXMoc2lkZSA9ICJyaWdodCIsCiAgICAgICAgICAgICBhdCA9IGMoMi41ZTUsIG1heF9sZW4pLAogICAgICAgICAgICAgbGFiZWxzLmNleCA9IDAuMjUqcGFyKCJjZXgiKSwKICAgICAgICAgICAgIHRpY2subGVuZ3RoID0gMgogICAgICAgICAgICAgKQogIAoKICAjIEFkZCBTQU1QTEUgeS1heGlzIGxhYmVsCiAgY2lyY29zLnRleHQoMmU2LCAyLjVlNSwKICAgICAgICAgICAgICBsYWJlbHMgPSBuYW1lcyhzdl9pbnZzKVtjb3VudGVyXSwKICAgICAgICAgICAgICBzZWN0b3IuaW5kZXggPSAiY2hyMSIsCiAgICAgICAgICAgICAgY2V4ID0gMC40KnBhcigiY2V4IikpCn0pCgoKY2lyY29zLmNsZWFyKCkKCmRldi5vZmYoKQpgYGAKCmBgYHtyLCBpbmNsdWRlID0gRn0KIyBjb3B5IHRvIHNhbWUgZGlyZWN0b3J5IGFzIGN1cnJlbnQgbm90ZWJvb2sKY3VycmVudF9kaXIgPSBkaXJuYW1lKHJzdHVkaW9hcGk6OmdldFNvdXJjZUVkaXRvckNvbnRleHQoKSRwYXRoKQoKbmV3X3BhdGggPSBmaWxlLnBhdGgoY3VycmVudF9kaXIsIGJhc2VuYW1lKG91dF9wbG90KSkKCmlmIChmaWxlLmV4aXN0cyhuZXdfcGF0aCkgIT0gVCl7CiAgZmlsZS5jb3B5KG91dF9wbG90LCBuZXdfcGF0aCkKfQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhiYXNlbmFtZShvdXRfcGxvdCkpCmBgYAoKIyBGaW5hbCBmaWd1cmUKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTQuNH0KZmluYWxfc3Z0eXBlID0gZ2dkcmF3KCkgKwogIGRyYXdfaW1hZ2UoaGVyZTo6aGVyZSgicGxvdHMiLCAic3ZfYW5hbHlzaXMiLCAiMjAyMTAyMjRfc3ZfZGVsc19saW5lcy5wbmciKSwKICAgICAgICAgICB4ID0gMCwgeSA9IDAsIHdpZHRoID0gMSwgaGVpZ2h0ID0gLjcsIHNjYWxlID0gMS4xMikgKwogIGRyYXdfcGxvdChzdnR5cGVfY291bnRzX3Bsb3QsCiAgICAgICAgICAgIHggPSAwLCB5ID0gLjcsIHdpZHRoID0gLjUsIGhlaWdodCA9IC4zKSArCiAgZHJhd19wbG90KHN2bGVuX2NvdW50c19wbG90LAogICAgICAgICAgICB4ID0gLjUsIHkgPSAuNywgd2lkdGggPS41LCBoZWlnaHQgPSAuMykgKwogIGRyYXdfcGxvdF9sYWJlbChsYWJlbCA9IGMoIkEiLCAiQiIsICJDIiksIHNpemUgPSAyNSwKICAgICAgICAgICAgICAgICAgeCA9IGMoMCwgLjUsIDApLCB5ID0gYygxLCAxLCAuNyksY29sb3IgPSAiIzRmMDk0MyIpCgpmaW5hbF9zdnR5cGUKYGBgCgpgYGB7ciwgZXZhbCA9IEZ9Cmdnc2F2ZShoZXJlOjpoZXJlKCJwbG90cyIsICJzdl9hbmFseXNpcyIsICIyMDIxMDMxOV9zdl9tYWluLnBuZyIpLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICBkcGkgPSA0MDAsCiAgICAgICB1bml0cyA9ICJjbSIsCiAgICAgICB3aWR0aCA9IDMwLAogICAgICAgaGVpZ2h0ID0gMzYpCmBgYAoK